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 loads the configuration file and sets the
18 ldap IP address, password, people dn, web dn, group dn. All these settings
19 were defined in a separate file ldap_config.py to avoid sharing them in
20 the SFA git as it contains sensible information.
23 def __init__(self, config_file='/etc/sfa/ldap_config.py'):
24 """Loads configuration from file /etc/sfa/ldap_config.py and set the
25 parameters for connection to LDAP.
30 execfile(config_file, self.__dict__)
32 self.config_file = config_file
33 # path to configuration data
34 self.config_path = os.path.dirname(config_file)
36 raise IOError, "Could not find or load the configuration file: %s" \
41 """ Set admin login and server configuration variables."""
44 """Fetch LdapConfig attributes (Ldap server connection parameters and
45 defines port , version and subtree scope.
48 #Iotlab PROD LDAP parameters
50 ldap_config = LdapConfig()
51 self.config = ldap_config
52 self.ldapHost = ldap_config.LDAP_IP_ADDRESS
53 self.ldapPeopleDN = ldap_config.LDAP_PEOPLE_DN
54 self.ldapGroupDN = ldap_config.LDAP_GROUP_DN
55 self.ldapAdminDN = ldap_config.LDAP_WEB_DN
56 self.ldapAdminPassword = ldap_config.LDAP_WEB_PASSWORD
57 self.ldapPort = ldap.PORT
58 self.ldapVersion = ldap.VERSION3
59 self.ldapSearchScope = ldap.SCOPE_SUBTREE
61 def connect(self, bind=True):
62 """Enables connection to the LDAP server.
64 :param bind: Set the bind parameter to True if a bind is needed
65 (for add/modify/delete operations). Set to False otherwise.
67 :returns: dictionary with status of the connection. True if Successful,
68 False if not and in this case the error
69 message( {'bool', 'message'} ).
74 self.ldapserv = ldap.open(self.ldapHost)
75 except ldap.LDAPError, error:
76 return {'bool': False, 'message': error}
78 # Bind with authentification
88 :returns: dictionary with the bind status. True if Successful,
89 False if not and in this case the error message( {'bool', 'message'} )
94 # Opens a connection after a call to ldap.open in connect:
95 self.ldapserv = ldap.initialize("ldap://" + self.ldapHost)
97 # Bind/authenticate with a user with apropriate
98 #rights to add objects
99 self.ldapserv.simple_bind_s(self.ldapAdminDN, \
100 self.ldapAdminPassword)
102 except ldap.LDAPError, error:
103 return {'bool': False, 'message': error}
105 return {'bool': True}
108 """ Close the LDAP connection.
110 Can throw an exception if the unbinding fails.
114 self.ldapserv.unbind_s()
115 except ldap.LDAPError, error:
116 return {'bool': False, 'message': error}
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 that
130 can be found in a random generated password.
133 self.login_max_length = 8
134 self.length_password = 8
135 self.chars_password = ['!', '$', '(',')', '*', '+', ',', '-', '.',
136 '0', '1', '2', '3', '4', '5', '6', '7', '8',
137 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
138 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
139 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
140 '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
141 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
142 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
146 def clean_user_names(record):
149 Removes special characters such as '-', '_' , '[', ']' and ' ' from the
150 first name and last name.
152 :param record: user's record
154 :returns: lower_first_name and lower_last_name if they were found
155 in the user's record. Return None, none otherwise.
156 :rtype: string, string or None, None.
159 if 'first_name' in record and 'last_name' in record:
160 #Remove all special characters from first_name/last name
161 lower_first_name = record['first_name'].replace('-', '')\
162 .replace('_', '').replace('[', '')\
163 .replace(']', '').replace(' ', '')\
165 lower_last_name = record['last_name'].replace('-', '')\
166 .replace('_', '').replace('[', '')\
167 .replace(']', '').replace(' ', '')\
169 return lower_first_name, lower_last_name
174 def extract_name_from_email(record):
177 When there is no valid first name and last name in the record,
178 the email is used to generate the login. Here, we assume the email
179 is firstname.lastname@something.smthg. The first name and last names
180 are extracted from the email, special charcaters are removed and
181 they are changed into lower case.
183 :param record: user's data
185 :returns: the first name and last name taken from the user's email.
186 lower_first_name, lower_last_name.
187 :rtype: string, string
191 email = record['email']
192 email = email.split('@')[0].lower()
193 lower_first_name = None
194 lower_last_name = None
195 #Assume there is first name and last name in email
196 #if there is a separator
197 separator_list = ['.', '_', '-']
198 for sep in separator_list:
200 mail = email.split(sep)
201 lower_first_name = mail[0]
202 lower_last_name = mail[1]
205 #Otherwise just take the part before the @ as the
206 #lower_first_name and lower_last_name
207 if lower_first_name is None:
208 lower_first_name = email
209 lower_last_name = email
211 return lower_first_name, lower_last_name
213 def get_user_firstname_lastname(self, record):
216 Get the user first name and last name from the information we have in
219 :param record: user's information
221 :returns: the user's first name and last name.
223 .. seealso:: clean_user_names
224 .. seealso:: extract_name_from_email
227 lower_first_name, lower_last_name = self.clean_user_names(record)
229 #No first name and last name check email
230 if lower_first_name is None and lower_last_name is None:
232 lower_first_name, lower_last_name = \
233 self.extract_name_from_email(record)
235 return lower_first_name, lower_last_name
237 def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
240 Algorithm to select sets of characters from the first name and last
241 name, depending on the lenght of the last name and the maximum login
242 length which in our case is set to 8 characters.
244 :param lower_first_name: user's first name in lower case.
245 :param lower_last_name: usr's last name in lower case.
246 :returns: user's login
250 length_last_name = len(lower_last_name)
251 self.login_max_length = 8
253 #Try generating a unique login based on first name and last name
255 if length_last_name >= self.login_max_length:
256 login = lower_last_name[0:self.login_max_length]
258 logger.debug("login : %s index : %s" % (login, index))
259 elif length_last_name >= 4:
260 login = lower_last_name
262 logger.debug("login : %s index : %s" % (login, index))
263 elif length_last_name == 3:
264 login = lower_first_name[0:1] + lower_last_name
266 logger.debug("login : %s index : %s" % (login, index))
267 elif length_last_name == 2:
268 if len(lower_first_name) >= 2:
269 login = lower_first_name[0:2] + lower_last_name
271 logger.debug("login : %s index : %s" % (login, index))
273 logger.error("LoginException : \
274 Generation login error with \
275 minimum four characters")
278 logger.error("LDAP LdapGenerateUniqueLogin failed : \
279 impossible to generate unique login for %s %s"
280 % (lower_first_name, lower_last_name))
283 def generate_password(self):
286 Generate a password upon adding a new user in LDAP Directory
287 (8 characters length). The generated password is composed of characters
288 from the chars_password list.
290 :returns: the randomly generated password
296 length = len(self.chars_password)
297 for index in range(self.length_password):
298 char_index = random.randint(0, length - 1)
299 password += self.chars_password[char_index]
304 def encrypt_password(password):
307 Use passlib library to make a RFC2307 LDAP encrypted password salt size
308 is 8, use sha-1 algorithm.
310 :param password: password not encrypted.
311 :type password: string
312 :returns: Returns encrypted password.
316 #Keep consistency with Java Iotlab's LDAP API
317 #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
318 return lssha.encrypt(password, salt_size=8)
322 """Defines functions to insert and search entries in the LDAP.
326 logger.setLevelDebug()
331 self.login_pwd = LoginPassword()
332 self.authname = config.SFA_REGISTRY_ROOT_AUTH
333 self.conn = ldap_co()
334 self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
335 self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
336 self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
337 self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
338 self.baseDN = self.conn.ldapPeopleDN
339 self.ldapShell = '/bin/bash'
342 def LdapGenerateUniqueLogin(self, record):
345 Generate login for adding a new user in LDAP Directory
346 (four characters minimum length). Get proper last name and
347 first name so that the user's login can be generated.
349 :param record: Record must contain first_name and last_name.
351 :returns: the generated login for the user described with record if the
352 login generation is successful, None if it fails.
353 :rtype: string or None
356 #For compatibility with other ldap func
357 if 'mail' in record and 'email' not in record:
358 record['email'] = record['mail']
360 lower_first_name, lower_last_name = \
361 self.login_pwd.get_user_firstname_lastname(record)
363 index, login = self.login_pwd.choose_sets_chars_for_login(
364 lower_first_name, lower_last_name)
366 login_filter = '(uid=' + login + ')'
369 #Check if login already in use
371 while (len(self.LdapSearch(login_filter, get_attrs)) is not 0):
375 logger.error("LoginException : Generation login error \
376 with minimum four characters")
380 lower_first_name[0:index] + \
381 lower_last_name[0:self.login_pwd.login_max_length-index]
382 login_filter = '(uid=' + login + ')'
384 print "lower_first_name - lower_last_name too short"
386 logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s" % (login))
389 except ldap.LDAPError, error:
390 logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" % (error))
393 def find_max_uidNumber(self):
394 """Find the LDAP max uidNumber (POSIX uid attribute).
396 Used when adding a new user in LDAP Directory
398 :returns: max uidNumber + 1
402 #First, get all the users in the LDAP
403 get_attrs = "(uidNumber=*)"
404 login_filter = ['uidNumber']
406 result_data = self.LdapSearch(get_attrs, login_filter)
407 #It there is no user in LDAP yet, First LDAP user
408 if result_data == []:
409 max_uidnumber = self.ldapUserUidNumberMin
410 #Otherwise, get the highest uidNumber
413 uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
414 logger.debug("LDAPapi.py \tfind_max_uidNumber \
415 uidNumberList %s " %(uidNumberList))
416 max_uidnumber = max(uidNumberList) + 1
418 return str(max_uidnumber)
421 def get_ssh_pkey(self, record):
422 """TODO ; Get ssh public key from sfa record
423 To be filled by N. Turro ? or using GID pl way?
429 #TODO Handle OR filtering in the ldap query when
430 #dealing with a list of records instead of doing a for loop in GetPersons
431 def make_ldap_filters_from_record(record=None):
432 """Helper function to make LDAP filter requests out of SFA records.
434 :param record: user's sfa record. Should contain first_name,last_name,
435 email or mail, and if the record is enabled or not. If the dict
436 record does not have all of these, must at least contain the user's
439 :returns: LDAP request
446 if 'first_name' in record and 'last_name' in record:
447 req_ldapdict['cn'] = str(record['first_name'])+" "\
448 + str(record['last_name'])
449 if 'email' in record :
450 req_ldapdict['mail'] = record['email']
452 req_ldapdict['mail'] = record['mail']
453 if 'enabled' in record:
454 if record['enabled'] == True :
455 req_ldapdict['shadowExpire'] = '-1'
457 req_ldapdict['shadowExpire'] = '0'
459 #Hrn should not be part of the filter because the hrn
460 #presented by a certificate of a SFA user not imported in
461 #Iotlab does not include the iotlab login in it
462 #Plus, the SFA user may already have an account with iotlab
463 #using another login.
467 logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
468 record %s req_ldapdict %s" \
469 %(record, req_ldapdict))
471 for k in req_ldapdict:
472 req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
473 if len(req_ldapdict.keys()) >1 :
474 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
476 req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
482 def make_ldap_attributes_from_record(self, record):
485 When adding a new user to Iotlab's LDAP, creates an attributes
486 dictionnary from the SFA record understandable by LDAP. Generates the
487 user's LDAP login.User is automatically validated (account enabled)
488 and described as a SFA USER FROM OUTSIDE IOTLAB.
490 :param record: must contain the following keys and values:
491 first_name, last_name, mail, pkey (ssh key).
493 :returns: dictionary of attributes using LDAP data structure model.
499 attrs['objectClass'] = ["top", "person", "inetOrgPerson",
500 "organizationalPerson", "posixAccount",
501 "shadowAccount", "systemQuotas",
504 attrs['uid'] = self.LdapGenerateUniqueLogin(record)
506 attrs['givenName'] = str(record['first_name']).lower().capitalize()
507 attrs['sn'] = str(record['last_name']).lower().capitalize()
508 attrs['cn'] = attrs['givenName'] + ' ' + attrs['sn']
509 attrs['gecos'] = attrs['givenName'] + ' ' + attrs['sn']
512 attrs['givenName'] = attrs['uid']
513 attrs['sn'] = attrs['uid']
514 attrs['cn'] = attrs['uid']
515 attrs['gecos'] = attrs['uid']
517 attrs['quota'] = self.ldapUserQuotaNFS
518 attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
519 attrs['loginShell'] = self.ldapShell
520 attrs['gidNumber'] = self.ldapUserGidNumber
521 attrs['uidNumber'] = self.find_max_uidNumber()
522 attrs['mail'] = record['mail'].lower()
524 attrs['sshPublicKey'] = record['pkey']
526 attrs['sshPublicKey'] = self.get_ssh_pkey(record)
529 #Password is automatically generated because SFA user don't go
530 #through the Iotlab website used to register new users,
531 #There is no place in SFA where users can enter such information
533 #If the user wants to set his own password , he must go to the Iotlab
535 password = self.login_pwd.generate_password()
536 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
538 #Account automatically validated (no mail request to admins)
539 #Set to 0 to disable the account, -1 to enable it,
540 attrs['shadowExpire'] = '-1'
542 #Motivation field in Iotlab
543 attrs['description'] = 'SFA USER FROM OUTSIDE SENSLAB'
545 attrs['ou'] = 'SFA' #Optional: organizational unit
546 #No info about those here:
547 attrs['l'] = 'To be defined'#Optional: Locality.
548 attrs['st'] = 'To be defined' #Optional: state or province (country).
554 def LdapAddUser(self, record) :
555 """Add SFA user to LDAP if it is not in LDAP yet.
557 :param record: dictionnary with the user's data.
558 :returns: a dictionary with the status (Fail= False, Success= True)
559 and the uid of the newly added user if successful, or the error
560 meassage it is not. Dict has keys bool and message in case of
561 failure, and bool uid in case of success.
564 .. seealso:: make_ldap_filters_from_record
567 logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
568 user_ldap_attrs = self.make_ldap_attributes_from_record(record)
571 #Check if user already in LDAP wih email, first name and last name
572 filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
573 user_exist = self.LdapSearch(filter_by)
575 logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
576 already exists" %(user_ldap_attrs['sn'], \
577 user_ldap_attrs['mail']))
578 return {'bool': False}
581 result = self.conn.connect()
585 # A dict to help build the "body" of the object
586 logger.debug(" \r\n \t LDAP LdapAddUser attrs %s "
589 # The dn of our new entry/object
590 dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
593 ldif = modlist.addModlist(user_ldap_attrs)
594 logger.debug("LDAPapi.py add attrs %s \r\n ldif %s"
595 % (user_ldap_attrs, ldif))
596 self.conn.ldapserv.add_s(dn, ldif)
598 logger.info("Adding user %s login %s in LDAP"
599 % (user_ldap_attrs['cn'], user_ldap_attrs['uid']))
600 except ldap.LDAPError, error:
601 logger.log_exc("LDAP Add Error %s" % error)
602 return {'bool': False, 'message': error}
605 return {'bool': True, 'uid': user_ldap_attrs['uid']}
609 def LdapDelete(self, person_dn):
610 """Deletes a person in LDAP. Uses the dn of the user.
612 :param person_dn: user's ldap dn.
613 :type person_dn: string
614 :returns: dictionary with bool True if successful, bool False
615 and the error if not.
620 result = self.conn.connect()
623 self.conn.ldapserv.delete_s(person_dn)
625 return {'bool': True}
627 except ldap.LDAPError, error:
628 logger.log_exc("LDAP Delete Error %s" %error)
629 return {'bool': False, 'message': error}
631 def LdapDeleteUser(self, record_filter):
632 """Deletes a SFA person in LDAP, based on the user's hrn.
634 :param record_filter: Filter to find the user to be deleted. Must
635 contain at least the user's email.
636 :type record_filter: dict
637 :returns: dict with bool True if successful, bool False and error
641 .. seealso:: LdapFindUser docstring for more info on record filter.
642 .. seealso:: LdapDelete for user deletion
645 #Find uid of the person
646 person = self.LdapFindUser(record_filter, [])
647 logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s"
648 % (record_filter, person))
651 dn = 'uid=' + person['uid'] + "," + self.baseDN
653 return {'bool': False}
655 result = self.LdapDelete(dn)
658 def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
659 """ Modifies a LDAP entry, replaces user's old attributes with
662 :param dn: user's absolute name in the LDAP hierarchy.
663 :param old_attributes_dict: old user's attributes. Keys must match
664 the ones used in the LDAP model.
665 :param new_attributes_dict: new user's attributes. Keys must match
666 the ones used in the LDAP model.
668 :type old_attributes_dict: dict
669 :type new_attributes_dict: dict
670 :returns: dict bool True if Successful, bool False if not.
675 ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
676 # Connect and bind/authenticate
677 result = self.conn.connect()
680 self.conn.ldapserv.modify_s(dn, ldif)
682 return {'bool': True}
683 except ldap.LDAPError, error:
684 logger.log_exc("LDAP LdapModify Error %s" % error)
685 return {'bool': False}
688 def LdapModifyUser(self, user_record, new_attributes_dict):
691 Gets the record from one user based on the user sfa recordand changes
692 the attributes according to the specified new_attributes. Do not use
693 this if we need to modify the uid. Use a ModRDN operation instead
694 ( modify relative DN ).
696 :param user_record: sfa user record.
697 :param new_attributes_dict: new user attributes, keys must be the
698 same as the LDAP model.
699 :type user_record: dict
700 :type new_attributes_dict: dict
701 :returns: bool True if successful, bool False if not.
704 .. seealso:: make_ldap_filters_from_record for info on what is mandatory
706 .. seealso:: make_ldap_attributes_from_record for the LDAP objectclass.
709 if user_record is None:
710 logger.error("LDAP \t LdapModifyUser Need user record ")
711 return {'bool': False}
713 #Get all the attributes of the user_uid_login
714 #person = self.LdapFindUser(record_filter,[])
715 req_ldap = self.make_ldap_filters_from_record(user_record)
716 person_list = self.LdapSearch(req_ldap, [])
717 logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s"
720 if person_list and len(person_list) > 1:
721 logger.error("LDAP \t LdapModifyUser Too many users returned")
722 return {'bool': False}
723 if person_list is None:
724 logger.error("LDAP \t LdapModifyUser User %s doesn't exist "
726 return {'bool': False}
728 # The dn of our existing entry/object
729 #One result only from ldapSearch
730 person = person_list[0][1]
731 dn = 'uid=' + person['uid'][0] + "," + self.baseDN
733 if new_attributes_dict:
735 for k in new_attributes_dict:
740 logger.debug(" LDAPapi.py \t LdapModifyUser new_attributes %s"
741 % (new_attributes_dict))
742 result = self.LdapModify(dn, old, new_attributes_dict)
745 logger.error("LDAP \t LdapModifyUser No new attributes given. ")
746 return {'bool': False}
749 def LdapMarkUserAsDeleted(self, record):
752 Sets shadowExpire to 0, disabling the user in LDAP. Calls LdapModifyUser
753 to change the shadowExpire of the user.
755 :param record: the record of the user who has to be disabled.
756 Should contain first_name,last_name, email or mail, and if the
757 record is enabled or not. If the dict record does not have all of
758 these, must at least contain the user's email.
760 :returns: {bool: True} if successful or {bool: False} if not
763 .. seealso:: LdapModifyUser, make_ldap_attributes_from_record
768 new_attrs['shadowExpire'] = '0'
769 logger.debug(" LDAPapi.py \t LdapMarkUserAsDeleted ")
770 ret = self.LdapModifyUser(record, new_attrs)
773 def LdapResetPassword(self, record):
774 """Resets password for the user whose record is the parameter and
775 changes the corresponding entry in the LDAP.
777 :param record: user's sfa record whose Ldap password must be reset.
778 Should contain first_name,last_name,
779 email or mail, and if the record is enabled or not. If the dict
780 record does not have all of these, must at least contain the user's
783 :returns: return value of LdapModifyUser. True if successful, False
786 .. seealso:: LdapModifyUser, make_ldap_attributes_from_record
789 password = self.login_pwd.generate_password()
791 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
792 logger.debug("LDAP LdapResetPassword encrypt_password %s"
793 % (attrs['userPassword']))
794 result = self.LdapModifyUser(record, attrs)
798 def LdapSearch(self, req_ldap=None, expected_fields=None):
800 Used to search directly in LDAP, by using ldap filters and return
801 fields. When req_ldap is None, returns all the entries in the LDAP.
803 :param req_ldap: ldap style request, with appropriate filters,
805 :param expected_fields: Fields in the user ldap entry that has to be
806 returned. If None is provided, will return 'mail', 'givenName',
807 'sn', 'uid', 'sshPublicKey', 'shadowExpire'.
808 :type req_ldap: string
809 :type expected_fields: list
811 .. seealso:: make_ldap_filters_from_record for req_ldap format.
814 result = self.conn.connect(bind=False)
817 return_fields_list = []
818 if expected_fields is None:
819 return_fields_list = ['mail', 'givenName', 'sn', 'uid',
820 'sshPublicKey', 'shadowExpire']
822 return_fields_list = expected_fields
823 #No specifc request specified, get the whole LDAP
827 logger.debug("LDAP.PY \t LdapSearch req_ldap %s \
828 return_fields_list %s" \
829 %(req_ldap, return_fields_list))
832 msg_id = self.conn.ldapserv.search(
833 self.baseDN, ldap.SCOPE_SUBTREE,
834 req_ldap, return_fields_list)
835 #Get all the results matching the search from ldap in one
837 result_type, result_data = \
838 self.conn.ldapserv.result(msg_id, 1)
842 logger.debug("LDAP.PY \t LdapSearch result_data %s"
847 except ldap.LDAPError, error:
848 logger.log_exc("LDAP LdapSearch Error %s" % error)
852 logger.error("LDAP.PY \t Connection Failed")
855 def _process_ldap_info_for_all_users(self, result_data):
856 """Process the data of all enabled users in LDAP.
858 :param result_data: Contains information of all enabled users in LDAP
859 and is coming from LdapSearch.
860 :param result_data: list
862 .. seealso:: LdapSearch
866 logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s "
868 for ldapentry in result_data:
869 logger.debug(" LDAP.py _process_ldap_info_for_all_users \
870 ldapentry name : %s " % (ldapentry[1]['uid'][0]))
871 tmpname = ldapentry[1]['uid'][0]
872 hrn = self.authname + "." + tmpname
874 tmpemail = ldapentry[1]['mail'][0]
875 if ldapentry[1]['mail'][0] == "unknown":
881 'pkey': ldapentry[1]['sshPublicKey'][0],
882 #'uid': ldapentry[1]['uid'][0],
885 #'email': ldapentry[1]['mail'][0],
886 'first_name': ldapentry[1]['givenName'][0],
887 'last_name': ldapentry[1]['sn'][0],
890 'authority': self.authname,
891 'peer_authority': '',
895 except KeyError, error:
896 logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s"
902 def _process_ldap_info_for_one_user(self, record, result_data):
905 Put the user's ldap data into shape. Only deals with one user
906 record and one user data from ldap.
908 :param record: user record
909 :param result_data: Raw ldap data coming from LdapSearch
910 :returns: user's data dict with 'type','pkey','uid', 'email',
911 'first_name' 'last_name''serial''authority''peer_authority'
914 :type result_data: list
918 #One entry only in the ldap data because we used a filter
919 #to find one user only
920 ldapentry = result_data[0][1]
921 logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" % (ldapentry))
922 tmpname = ldapentry['uid'][0]
924 tmpemail = ldapentry['mail'][0]
925 if ldapentry['mail'][0] == "unknown":
929 peer_authority = None
932 parent_hrn = get_authority(hrn)
933 if parent_hrn != self.authname:
934 peer_authority = parent_hrn
935 #In case the user was not imported from Iotlab LDAP
936 #but from another federated site, has an account in
937 #iotlab but currently using his hrn from federated site
938 #then the login is different from the one found in its hrn
939 if tmpname != hrn.split('.')[1]:
946 'pkey': ldapentry['sshPublicKey'],
947 #'uid': ldapentry[1]['uid'][0],
950 #'email': ldapentry[1]['mail'][0],
951 'first_name': ldapentry['givenName'][0],
952 'last_name': ldapentry['sn'][0],
955 'authority': parent_hrn,
956 'peer_authority': peer_authority,
962 def LdapFindUser(self, record=None, is_user_enabled=None,
963 expected_fields=None):
966 Search a SFA user with a hrn. User should be already registered
969 :param record: sfa user's record. Should contain first_name,last_name,
970 email or mail. If no record is provided, returns all the users found
973 :param is_user_enabled: is the user's iotlab account already valid.
974 :type is_user_enabled: Boolean.
975 :returns: LDAP entries from ldap matching the filter provided. Returns
976 a single entry if one filter has been given and a list of
983 custom_record['enabled'] = is_user_enabled
985 custom_record.update(record)
987 req_ldap = self.make_ldap_filters_from_record(custom_record)
988 return_fields_list = []
989 if expected_fields is None:
990 return_fields_list = ['mail', 'givenName', 'sn', 'uid',
993 return_fields_list = expected_fields
995 result_data = self.LdapSearch(req_ldap, return_fields_list)
996 logger.debug("LDAP.PY \t LdapFindUser result_data %s" % (result_data))
998 if len(result_data) == 0:
1000 #Asked for a specific user
1001 if record is not None:
1002 results = self._process_ldap_info_for_one_user(record, result_data)
1005 #Asked for all users in ldap
1006 results = self._process_ldap_info_for_all_users(result_data)