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
17 Ldap configuration class@make_ldap_filters_from_record and sets the
18 ldap IP address, password, people dn, web dn, group dn
19 . All these settings were defined in a separate
20 file ldap_config.py to avoid sharing them in the SFA git as it contains
24 def __init__(self, config_file='/etc/sfa/ldap_config.py'):
25 """Loads configuration from file /etc/sfa/ldap_config.py and set the
26 parameters for connection to LDAP.
31 execfile(config_file, self.__dict__)
33 self.config_file = config_file
34 # path to configuration data
35 self.config_path = os.path.dirname(config_file)
37 raise IOError, "Could not find or load the configuration file: %s" \
42 """ Set admin login and server configuration variables."""
45 """Fetch LdapConfig attributes (Ldap server connection parameters and
46 defines port , version and subtree scope.
49 #Iotlab PROD LDAP parameters
51 ldap_config = LdapConfig()
52 self.config = ldap_config
53 self.ldapHost = ldap_config.LDAP_IP_ADDRESS
54 self.ldapPeopleDN = ldap_config.LDAP_PEOPLE_DN
55 self.ldapGroupDN = ldap_config.LDAP_GROUP_DN
56 self.ldapAdminDN = ldap_config.LDAP_WEB_DN
57 self.ldapAdminPassword = ldap_config.LDAP_WEB_PASSWORD
58 self.ldapPort = ldap.PORT
59 self.ldapVersion = ldap.VERSION3
60 self.ldapSearchScope = ldap.SCOPE_SUBTREE
62 def connect(self, bind=True):
63 """Enables connection to the LDAP server.
65 :param bind: Set the bind parameter to True if a bind is needed
66 (for add/modify/delete operations). Set to False otherwise.
68 :returns: dictionary with status of the connection. True if Successful,
69 False if not and in this case the error
70 message( {'bool', 'message'} ).
75 self.ldapserv = ldap.open(self.ldapHost)
76 except ldap.LDAPError, error:
77 return {'bool': False, 'message': error}
79 # Bind with authentification
89 :returns: dictionary with the bind status. True if Successful,
90 False if not and in this case the error message( {'bool', 'message'} )
95 # Opens a connection after a call to ldap.open in connect:
96 self.ldapserv = ldap.initialize("ldap://" + self.ldapHost)
98 # Bind/authenticate with a user with apropriate
99 #rights to add objects
100 self.ldapserv.simple_bind_s(self.ldapAdminDN, \
101 self.ldapAdminPassword)
103 except ldap.LDAPError, error:
104 return {'bool': False, 'message': error}
106 return {'bool': True}
109 """ Close the LDAP connection.
111 Can throw an exception if the unbinding fails.
115 self.ldapserv.unbind_s()
116 except ldap.LDAPError, error:
117 return {'bool': False, 'message': error}
120 class LoginPassword():
123 Class to handle login and password generation, using custom login generation
130 Sets password and login maximum length, and defines the characters
131 that can be found in a random generated password.
134 self.login_max_length = 8
135 self.length_password = 8
136 self.chars_password = ['!', '$', '(',')', '*', '+', ',', '-', '.',
137 '0', '1', '2', '3', '4', '5', '6', '7', '8',
138 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
139 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
140 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
141 '_', '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',
147 def clean_user_names(record):
150 Removes special characters such as
151 '-', '_' , '[', ']' and ' ' from the first name and last name.
153 :param record: user's record
155 :returns: lower_first_name and lower_last_name if they were found
156 in the user's record. Return None, none otherwise.
157 :rtype: string, string or None, None.
160 if 'first_name' in record and 'last_name' in record:
161 #Remove all special characters from first_name/last name
162 lower_first_name = record['first_name'].replace('-', '')\
163 .replace('_', '').replace('[', '')\
164 .replace(']', '').replace(' ', '')\
166 lower_last_name = record['last_name'].replace('-', '')\
167 .replace('_', '').replace('[', '')\
168 .replace(']', '').replace(' ', '')\
170 return lower_first_name, lower_last_name
175 def extract_name_from_email(record):
178 When there is no valid first name and last name in the record,
179 the email is used to generate the login. Here, we assume the email
180 is firstname.lastname@something.smthg. The first name and last names
181 are extracted from the email, special charcaters are removed and
182 they are changed into lower case.
184 :param record: user's data
186 :returns: the first name and last name taken from the user's email.
187 lower_first_name, lower_last_name.
188 :rtype: string, string
192 email = record['email']
193 email = email.split('@')[0].lower()
194 lower_first_name = None
195 lower_last_name = None
196 #Assume there is first name and last name in email
197 #if there is a separator
198 separator_list = ['.', '_', '-']
199 for sep in separator_list:
201 mail = email.split(sep)
202 lower_first_name = mail[0]
203 lower_last_name = mail[1]
206 #Otherwise just take the part before the @ as the
207 #lower_first_name and lower_last_name
208 if lower_first_name is None:
209 lower_first_name = email
210 lower_last_name = email
212 return lower_first_name, lower_last_name
214 def get_user_firstname_lastname(self, record):
217 Get the user first name and last name from the information
218 we have in the record.
220 :param record: user's information
222 :returns: the user's first name and last name.
224 .. seealso:: clean_user_names
225 .. seealso:: extract_name_from_email
228 lower_first_name, lower_last_name = self.clean_user_names(record)
230 #No first name and last name check email
231 if lower_first_name is None and lower_last_name is None:
233 lower_first_name, lower_last_name = \
234 self.extract_name_from_email(record)
236 return lower_first_name, lower_last_name
238 def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
241 Algorithm to select sets of characters from the first name and
242 last name, depending on the lenght of the last name and the
243 maximum login length which in our case is set to 8 characters.
245 :param lower_first_name: user's first name in lower case.
246 :param lower_last_name: usr's last name in lower case.
247 :returns: user's login
251 length_last_name = len(lower_last_name)
252 self.login_max_length = 8
254 #Try generating a unique login based on first name and last name
256 if length_last_name >= self.login_max_length:
257 login = lower_last_name[0:self.login_max_length]
259 logger.debug("login : %s index : %s" % (login, index))
260 elif length_last_name >= 4:
261 login = lower_last_name
263 logger.debug("login : %s index : %s" % (login, index))
264 elif length_last_name == 3:
265 login = lower_first_name[0:1] + lower_last_name
267 logger.debug("login : %s index : %s" % (login, index))
268 elif length_last_name == 2:
269 if len(lower_first_name) >= 2:
270 login = lower_first_name[0:2] + lower_last_name
272 logger.debug("login : %s index : %s" % (login, index))
274 logger.error("LoginException : \
275 Generation login error with \
276 minimum four characters")
279 logger.error("LDAP LdapGenerateUniqueLogin failed : \
280 impossible to generate unique login for %s %s"
281 % (lower_first_name, lower_last_name))
284 def generate_password(self):
287 Generate a password upon adding a new user in LDAP Directory
288 (8 characters length). The generated password is composed
289 of characters from the charsPassword list.
291 :returns: the randomly generated password
297 length = len(self.chars_password)
298 for index in range(self.length_password):
299 char_index = random.randint(0, length - 1)
300 password += self.chars_password[char_index]
305 def encrypt_password(password):
308 Use passlib library to make a RFC2307 LDAP encrypted password
309 salt size = 8, use sha-1 algorithm.
311 :param password: password not encrypted.
312 :type password: string
313 :returns: Returns encrypted password.
317 #Keep consistency with Java Iotlab's LDAP API
318 #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
319 return lssha.encrypt(password, salt_size=8)
323 """Defines functions to insert and search entries in the LDAP.
327 logger.setLevelDebug()
332 self.login_pwd = LoginPassword()
333 self.authname = config.SFA_REGISTRY_ROOT_AUTH
334 self.conn = ldap_co()
335 self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
336 self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
337 self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
338 self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
339 self.baseDN = self.conn.ldapPeopleDN
340 self.ldapShell = '/bin/bash'
343 def LdapGenerateUniqueLogin(self, record):
346 Generate login for adding a new user in LDAP Directory
347 (four characters minimum length). Get proper last name and
348 first name so that the user's login can be generated.
350 :param record: Record must contain first_name and last_name.
352 :returns: the generated login for the user described with record if the
353 login generation is successful, None if it fails.
354 :rtype: string or None
357 #For compatibility with other ldap func
358 if 'mail' in record and 'email' not in record:
359 record['email'] = record['mail']
361 lower_first_name, lower_last_name = \
362 self.login_pwd.get_user_firstname_lastname(record)
364 index, login = self.login_pwd.choose_sets_chars_for_login(
365 lower_first_name, lower_last_name)
367 login_filter = '(uid=' + login + ')'
370 #Check if login already in use
372 while (len(self.LdapSearch(login_filter, get_attrs)) is not 0):
376 logger.error("LoginException : Generation login error \
377 with minimum four characters")
381 lower_first_name[0:index] + \
382 lower_last_name[0:self.login_pwd.login_max_length-index]
383 login_filter = '(uid=' + login + ')'
385 print "lower_first_name - lower_last_name too short"
387 logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s" % (login))
390 except ldap.LDAPError, error:
391 logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" % (error))
394 def find_max_uidNumber(self):
395 """Find the LDAP max uidNumber (POSIX uid attribute).
397 Used when adding a new user in LDAP Directory
399 :returns: max uidNumber + 1
403 #First, get all the users in the LDAP
404 get_attrs = "(uidNumber=*)"
405 login_filter = ['uidNumber']
407 result_data = self.LdapSearch(get_attrs, login_filter)
408 #It there is no user in LDAP yet, First LDAP user
409 if result_data == []:
410 max_uidnumber = self.ldapUserUidNumberMin
411 #Otherwise, get the highest uidNumber
414 uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
415 logger.debug("LDAPapi.py \tfind_max_uidNumber \
416 uidNumberList %s " %(uidNumberList))
417 max_uidnumber = max(uidNumberList) + 1
419 return str(max_uidnumber)
422 def get_ssh_pkey(self, record):
423 """TODO ; Get ssh public key from sfa record
424 To be filled by N. Turro ? or using GID pl way?
430 #TODO Handle OR filtering in the ldap query when
431 #dealing with a list of records instead of doing a for loop in GetPersons
432 def make_ldap_filters_from_record(record=None):
433 """Helper function to make LDAP filter requests out of SFA records.
435 :param record: user's sfa record. Should contain first_name,last_name,
436 email or mail, and if the record is enabled or not. If the dict
437 record does not have all of these, must at least contain the user's
440 :returns: LDAP request
447 if 'first_name' in record and 'last_name' in record:
448 req_ldapdict['cn'] = str(record['first_name'])+" "\
449 + str(record['last_name'])
450 if 'email' in record :
451 req_ldapdict['mail'] = record['email']
453 req_ldapdict['mail'] = record['mail']
454 if 'enabled' in record:
455 if record['enabled'] == True :
456 req_ldapdict['shadowExpire'] = '-1'
458 req_ldapdict['shadowExpire'] = '0'
460 #Hrn should not be part of the filter because the hrn
461 #presented by a certificate of a SFA user not imported in
462 #Iotlab does not include the iotlab login in it
463 #Plus, the SFA user may already have an account with iotlab
464 #using another login.
468 logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
469 record %s req_ldapdict %s" \
470 %(record, req_ldapdict))
472 for k in req_ldapdict:
473 req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
474 if len(req_ldapdict.keys()) >1 :
475 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
477 req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
483 def make_ldap_attributes_from_record(self, record):
486 When adding a new user to Iotlab's LDAP, creates an attributes
487 dictionnary from the SFA record understandable by LDAP.
488 Generates the user's LDAP login.
489 User is automatically validated (account enabled) and described
490 as a SFA USER FROM OUTSIDE IOTLAB.
492 :param record: must contain the following keys and values:
493 first_name, last_name, mail, pkey (ssh key).
495 :returns: dictionary of attributes using LDAP data structure model.
501 attrs['objectClass'] = ["top", "person", "inetOrgPerson",
502 "organizationalPerson", "posixAccount",
503 "shadowAccount", "systemQuotas",
506 attrs['uid'] = self.LdapGenerateUniqueLogin(record)
508 attrs['givenName'] = str(record['first_name']).lower().capitalize()
509 attrs['sn'] = str(record['last_name']).lower().capitalize()
510 attrs['cn'] = attrs['givenName'] + ' ' + attrs['sn']
511 attrs['gecos'] = attrs['givenName'] + ' ' + attrs['sn']
514 attrs['givenName'] = attrs['uid']
515 attrs['sn'] = attrs['uid']
516 attrs['cn'] = attrs['uid']
517 attrs['gecos'] = attrs['uid']
519 attrs['quota'] = self.ldapUserQuotaNFS
520 attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
521 attrs['loginShell'] = self.ldapShell
522 attrs['gidNumber'] = self.ldapUserGidNumber
523 attrs['uidNumber'] = self.find_max_uidNumber()
524 attrs['mail'] = record['mail'].lower()
526 attrs['sshPublicKey'] = record['pkey']
528 attrs['sshPublicKey'] = self.get_ssh_pkey(record)
531 #Password is automatically generated because SFA user don't go
532 #through the Iotlab website used to register new users,
533 #There is no place in SFA where users can enter such information
535 #If the user wants to set his own password , he must go to the Iotlab
537 password = self.login_pwd.generate_password()
538 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
540 #Account automatically validated (no mail request to admins)
541 #Set to 0 to disable the account, -1 to enable it,
542 attrs['shadowExpire'] = '-1'
544 #Motivation field in Iotlab
545 attrs['description'] = 'SFA USER FROM OUTSIDE SENSLAB'
547 attrs['ou'] = 'SFA' #Optional: organizational unit
548 #No info about those here:
549 attrs['l'] = 'To be defined'#Optional: Locality.
550 attrs['st'] = 'To be defined' #Optional: state or province (country).
556 def LdapAddUser(self, record) :
557 """Add SFA user to LDAP if it is not in LDAP yet.
559 :param record: dictionnary with the user's data.
560 :returns: a dictionary with the status (Fail= False, Success= True)
561 and the uid of the newly added user if successful, or the error
562 meassage it is not. Dict has keys bool and message in case of
563 failure, and bool uid in case of success.
566 .. seealso:: make_ldap_filters_from_record
569 logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
570 user_ldap_attrs = self.make_ldap_attributes_from_record(record)
573 #Check if user already in LDAP wih email, first name and last name
574 filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
575 user_exist = self.LdapSearch(filter_by)
577 logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
578 already exists" %(user_ldap_attrs['sn'], \
579 user_ldap_attrs['mail']))
580 return {'bool': False}
583 result = self.conn.connect()
587 # A dict to help build the "body" of the object
588 logger.debug(" \r\n \t LDAP LdapAddUser attrs %s "
591 # The dn of our new entry/object
592 dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
595 ldif = modlist.addModlist(user_ldap_attrs)
596 logger.debug("LDAPapi.py add attrs %s \r\n ldif %s"
597 % (user_ldap_attrs, ldif))
598 self.conn.ldapserv.add_s(dn, ldif)
600 logger.info("Adding user %s login %s in LDAP"
601 % (user_ldap_attrs['cn'], user_ldap_attrs['uid']))
602 except ldap.LDAPError, error:
603 logger.log_exc("LDAP Add Error %s" % error)
604 return {'bool': False, 'message': error}
607 return {'bool': True, 'uid': user_ldap_attrs['uid']}
611 def LdapDelete(self, person_dn):
612 """Deletes a person in LDAP. Uses the dn of the user.
614 :param person_dn: user's ldap dn.
615 :type person_dn: string
616 :returns: dictionary with bool True if successful, bool False
617 and the error if not.
622 result = self.conn.connect()
625 self.conn.ldapserv.delete_s(person_dn)
627 return {'bool': True}
629 except ldap.LDAPError, error:
630 logger.log_exc("LDAP Delete Error %s" %error)
631 return {'bool': False, 'message': error}
633 def LdapDeleteUser(self, record_filter):
634 """Deletes a SFA person in LDAP, based on the user's hrn.
636 :param record_filter: Filter to find the user to be deleted. Must
637 contain at least the user's email.
638 :type record_filter: dict
639 :returns: dict with bool True if successful, bool False and error
643 .. seealso:: LdapFindUser docstring for more info on record filter.
644 .. seealso:: LdapDelete for user deletion
647 #Find uid of the person
648 person = self.LdapFindUser(record_filter, [])
649 logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s"
650 % (record_filter, person))
653 dn = 'uid=' + person['uid'] + "," + self.baseDN
655 return {'bool': False}
657 result = self.LdapDelete(dn)
660 def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
661 """ Modifies a LDAP entry, replaces user's old attributes with
664 :param dn: user's absolute name in the LDAP hierarchy.
665 :param old_attributes_dict: old user's attributes. Keys must match
666 the ones used in the LDAP model.
667 :param new_attributes_dict: new user's attributes. Keys must match
668 the ones used in the LDAP model.
670 :type old_attributes_dict: dict
671 :type new_attributes_dict: dict
672 :returns: dict bool True if Successful, bool False if not.
677 ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
678 # Connect and bind/authenticate
679 result = self.conn.connect()
682 self.conn.ldapserv.modify_s(dn, ldif)
684 return {'bool': True}
685 except ldap.LDAPError, error:
686 logger.log_exc("LDAP LdapModify Error %s" % error)
687 return {'bool': False}
690 def LdapModifyUser(self, user_record, new_attributes_dict):
693 Gets the record from one user based on the user sfa recordand changes
694 the attributes according to the specified new_attributes.
695 Do not use this if we need to modify the uid. Use a ModRDN
696 #operation instead ( modify relative DN )
698 :param user_record: sfa user record.
699 :param new_attributes_dict: new user attributes, keys must be the
700 same as the LDAP model.
701 :type user_record: dict
702 :type new_attributes_dict: dict
703 :returns: bool True if successful, bool False if not.
706 .. seealso:: make_ldap_filters_from_record for info on what is mandatory
708 .. seealso:: make_ldap_attributes_from_record for the LDAP objectclass.
711 if user_record is None:
712 logger.error("LDAP \t LdapModifyUser Need user record ")
713 return {'bool': False}
715 #Get all the attributes of the user_uid_login
716 #person = self.LdapFindUser(record_filter,[])
717 req_ldap = self.make_ldap_filters_from_record(user_record)
718 person_list = self.LdapSearch(req_ldap, [])
719 logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s"
722 if person_list and len(person_list) > 1:
723 logger.error("LDAP \t LdapModifyUser Too many users returned")
724 return {'bool': False}
725 if person_list is None:
726 logger.error("LDAP \t LdapModifyUser User %s doesn't exist "
728 return {'bool': False}
730 # The dn of our existing entry/object
731 #One result only from ldapSearch
732 person = person_list[0][1]
733 dn = 'uid=' + person['uid'][0] + "," + self.baseDN
735 if new_attributes_dict:
737 for k in new_attributes_dict:
742 logger.debug(" LDAPapi.py \t LdapModifyUser new_attributes %s"
743 % (new_attributes_dict))
744 result = self.LdapModify(dn, old, new_attributes_dict)
747 logger.error("LDAP \t LdapModifyUser No new attributes given. ")
748 return {'bool': False}
751 def LdapMarkUserAsDeleted(self, record):
754 Sets shadowExpire to 0, disabling the user in LDAP.
755 Calls LdapModifyUser to change the shadowExpire of the user.
757 :param record: the record of the user who has to be disabled.
758 Should contain first_name,last_name, email or mail, and if the
759 record is enabled or not. If the dict record does not have all of
760 these, must at least contain the user's email.
762 :returns: bool True if successful or bool False if not
765 .. seealso:: LdapModifyUser , make_ldap_attributes_from_record
770 new_attrs['shadowExpire'] = '0'
771 logger.debug(" LDAPapi.py \t LdapMarkUserAsDeleted ")
772 ret = self.LdapModifyUser(record, new_attrs)
775 def LdapResetPassword(self, record):
776 """Resets password for the user whose record is the parameter and
777 changes the corresponding entry in the LDAP.
779 :param record: user's sfa record whose Ldap password must be reset.
780 Should contain first_name,last_name,
781 email or mail, and if the record is enabled or not. If the dict
782 record does not have all of these, must at least contain the user's
785 :returns: return value of LdapModifyUser. True if successful, False
788 .. seealso:: LdapModifyUser, make_ldap_attributes_from_record
791 password = self.login_pwd.generate_password()
793 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
794 logger.debug("LDAP LdapResetPassword encrypt_password %s"
795 % (attrs['userPassword']))
796 result = self.LdapModifyUser(record, attrs)
800 def LdapSearch(self, req_ldap=None, expected_fields=None):
802 Used to search directly in LDAP, by using ldap filters and
804 When req_ldap is None, returns all the entries in the LDAP.
806 :param req_ldap: ldap style request, with appropriate filters,
808 :param expected_fields: Fields in the user ldap entry that has to be
809 returned. If None is provided, will return 'mail', 'givenName',
810 'sn', 'uid', 'sshPublicKey', 'shadowExpire'.
811 :type req_ldap: string
812 :type expected_fields: list
814 .. seealso:: make_ldap_filters_from_record for req_ldap format.
817 result = self.conn.connect(bind=False)
820 return_fields_list = []
821 if expected_fields is None:
822 return_fields_list = ['mail', 'givenName', 'sn', 'uid',
823 'sshPublicKey', 'shadowExpire']
825 return_fields_list = expected_fields
826 #No specifc request specified, get the whole LDAP
830 logger.debug("LDAP.PY \t LdapSearch req_ldap %s \
831 return_fields_list %s" \
832 %(req_ldap, return_fields_list))
835 msg_id = self.conn.ldapserv.search(
836 self.baseDN, ldap.SCOPE_SUBTREE,
837 req_ldap, return_fields_list)
838 #Get all the results matching the search from ldap in one
840 result_type, result_data = \
841 self.conn.ldapserv.result(msg_id, 1)
845 logger.debug("LDAP.PY \t LdapSearch result_data %s"
850 except ldap.LDAPError, error:
851 logger.log_exc("LDAP LdapSearch Error %s" % error)
855 logger.error("LDAP.PY \t Connection Failed")
858 def _process_ldap_info_for_all_users(self, result_data):
859 """Process the data of all enabled users in LDAP.
861 :param result_data: Contains information of all enabled users in LDAP
862 and is coming from LdapSearch.
863 :param result_data: list
865 .. seealso:: LdapSearch
869 logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s "
871 for ldapentry in result_data:
872 logger.debug(" LDAP.py _process_ldap_info_for_all_users \
873 ldapentry name : %s " % (ldapentry[1]['uid'][0]))
874 tmpname = ldapentry[1]['uid'][0]
875 hrn = self.authname + "." + tmpname
877 tmpemail = ldapentry[1]['mail'][0]
878 if ldapentry[1]['mail'][0] == "unknown":
884 'pkey': ldapentry[1]['sshPublicKey'][0],
885 #'uid': ldapentry[1]['uid'][0],
888 #'email': ldapentry[1]['mail'][0],
889 'first_name': ldapentry[1]['givenName'][0],
890 'last_name': ldapentry[1]['sn'][0],
893 'authority': self.authname,
894 'peer_authority': '',
898 except KeyError, error:
899 logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s"
905 def _process_ldap_info_for_one_user(self, record, result_data):
908 Put the user's ldap data into shape. Only deals with one user
909 record and one user data from ldap.
911 :param record: user record
912 :param result_data: Raw ldap data coming from LdapSearch
913 :returns: user's data dict with 'type','pkey','uid', 'email',
914 'first_name' 'last_name''serial''authority''peer_authority'
917 :type result_data: list
921 #One entry only in the ldap data because we used a filter
922 #to find one user only
923 ldapentry = result_data[0][1]
924 logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" % (ldapentry))
925 tmpname = ldapentry['uid'][0]
927 tmpemail = ldapentry['mail'][0]
928 if ldapentry['mail'][0] == "unknown":
932 peer_authority = None
935 parent_hrn = get_authority(hrn)
936 if parent_hrn != self.authname:
937 peer_authority = parent_hrn
938 #In case the user was not imported from Iotlab LDAP
939 #but from another federated site, has an account in
940 #iotlab but currently using his hrn from federated site
941 #then the login is different from the one found in its hrn
942 if tmpname != hrn.split('.')[1]:
949 'pkey': ldapentry['sshPublicKey'],
950 #'uid': ldapentry[1]['uid'][0],
953 #'email': ldapentry[1]['mail'][0],
954 'first_name': ldapentry['givenName'][0],
955 'last_name': ldapentry['sn'][0],
958 'authority': parent_hrn,
959 'peer_authority': peer_authority,
965 def LdapFindUser(self, record=None, is_user_enabled=None,
966 expected_fields=None):
969 Search a SFA user with a hrn. User should be already registered
972 :param record: sfa user's record. Should contain first_name,last_name,
973 email or mail. If no record is provided, returns all the users found
976 :param is_user_enabled: is the user's iotlab account already valid.
977 :type is_user_enabled: Boolean.
978 :returns: LDAP entries from ldap matching the filter provided. Returns
979 a single entry if one filter has been given and a list of
986 custom_record['enabled'] = is_user_enabled
988 custom_record.update(record)
990 req_ldap = self.make_ldap_filters_from_record(custom_record)
991 return_fields_list = []
992 if expected_fields is None:
993 return_fields_list = ['mail', 'givenName', 'sn', 'uid',
996 return_fields_list = expected_fields
998 result_data = self.LdapSearch(req_ldap, return_fields_list)
999 logger.debug("LDAP.PY \t LdapFindUser result_data %s" % (result_data))
1001 if len(result_data) == 0:
1003 #Asked for a specific user
1004 if record is not None:
1005 results = self._process_ldap_info_for_one_user(record, result_data)
1008 #Asked for all users in ldap
1009 results = self._process_ldap_info_for_all_users(result_data)