Adding and formatting documentation for Sphinx.
[sfa.git] / sfa / iotlab / LDAPapi.py
index 98a72ec..254f994 100644 (file)
@@ -1,19 +1,41 @@
+"""
+This API is adapted for OpenLDAP.
+The file contains all LDAP classes and methods needed to:
+ - Load the LDAP connection configuration file (login, address..) with
+    LdapConfig
+ - Connect to LDAP with ldap_co
+ - Create a unique LDAP login and password for a user based on his email or
+    last name and first name with LoginPassword.
+ -  Manage entries in LDAP using SFA records with LDAPapi
+ (Search, Add, Delete, Modify)
+
+"""
 import random
 from passlib.hash import ldap_salted_sha1 as lssha
+
 from sfa.util.xrn import get_authority
-import ldap
+from sfa.util.sfalogging import logger
 from sfa.util.config import Config
 
-
+import ldap
 import ldap.modlist as modlist
-from sfa.util.sfalogging import logger
-import os.path
 
-#API for OpenLDAP
+import os.path
 
 
 class LdapConfig():
-    def __init__(self, config_file =  '/etc/sfa/ldap_config.py'):
+    """
+    Ldap configuration class loads the configuration file and sets the
+    ldap IP address, password, people dn, web dn, group dn. All these settings
+    were defined in a separate file  ldap_config.py to avoid sharing them in
+    the SFA git as it contains sensible information.
+
+    """
+    def __init__(self, config_file='/etc/sfa/ldap_config.py'):
+        """Loads configuration from file /etc/sfa/ldap_config.py and set the
+        parameters for connection to LDAP.
+
+        """
 
         try:
             execfile(config_file, self.__dict__)
@@ -23,13 +45,17 @@ class LdapConfig():
             self.config_path = os.path.dirname(config_file)
         except IOError:
             raise IOError, "Could not find or load the configuration file: %s" \
-                            % config_file
+                % config_file
 
 
 class ldap_co:
     """ Set admin login and server configuration variables."""
 
     def __init__(self):
+        """Fetch LdapConfig attributes (Ldap server connection parameters and
+        defines port , version and subtree scope.
+
+        """
         #Iotlab PROD LDAP parameters
         self.ldapserv = None
         ldap_config = LdapConfig()
@@ -39,24 +65,20 @@ class ldap_co:
         self.ldapGroupDN = ldap_config.LDAP_GROUP_DN
         self.ldapAdminDN = ldap_config.LDAP_WEB_DN
         self.ldapAdminPassword = ldap_config.LDAP_WEB_PASSWORD
-
-
         self.ldapPort = ldap.PORT
-        self.ldapVersion  = ldap.VERSION3
+        self.ldapVersion = ldap.VERSION3
         self.ldapSearchScope = ldap.SCOPE_SUBTREE
 
-
     def connect(self, bind=True):
-        """
-        Enables connection to the LDAP server.
-        :param bind : Set the bind parameter to True if a bind is needed
-        (for add/modify/delete operations).
-        Set to False otherwise.
-
-        :type bind : boolean
-        :return: dictionary with status of the connection. True if Successful,
-        False if not and in this case the error message( {'bool', 'message'} )
-        :rtype:dict
+        """Enables connection to the LDAP server.
+
+        :param bind: Set the bind parameter to True if a bind is needed
+            (for add/modify/delete operations). Set to False otherwise.
+        :type bind: boolean
+        :returns: dictionary with status of the connection. True if Successful,
+            False if not and in this case the error
+            message( {'bool', 'message'} ).
+        :rtype: dict
 
         """
         try:
@@ -73,8 +95,9 @@ class ldap_co:
 
     def bind(self):
         """ Binding method.
-        :return: dictionary with the bind status. True if Successful,
-        False if not and in this case the error message( {'bool', 'message'} )
+
+        :returns: dictionary with the bind status. True if Successful,
+            False if not and in this case the error message({'bool','message'})
         :rtype: dict
 
         """
@@ -84,8 +107,8 @@ class ldap_co:
 
             # Bind/authenticate with a user with apropriate
             #rights to add objects
-            self.ldapserv.simple_bind_s(self.ldapAdminDN, \
-                                    self.ldapAdminPassword)
+            self.ldapserv.simple_bind_s(self.ldapAdminDN,
+                                        self.ldapAdminPassword)
 
         except ldap.LDAPError, error:
             return {'bool': False, 'message': error}
@@ -96,6 +119,9 @@ class ldap_co:
         """ Close the LDAP connection.
 
         Can throw an exception if the unbinding fails.
+        :returns: dictionary with the bind status if fails.
+            False if not and in this case the error message({'bool','message'})
+        :rtype: dict or None
 
         """
         try:
@@ -114,8 +140,8 @@ class LoginPassword():
     def __init__(self):
         """
 
-        Sets password  and login maximum length, and defines the characters
-        that can be found in a random generated password.
+        Sets password  and login maximum length, and defines the characters that
+        can be found in a random generated password.
 
         """
         self.login_max_length = 8
@@ -134,13 +160,13 @@ class LoginPassword():
     def clean_user_names(record):
         """
 
-        Removes special characters such as
-        '-', '_' , '[', ']' and ' ' from the first name and last name.
+        Removes special characters such as '-', '_' , '[', ']' and ' ' from the
+        first name and last name.
 
         :param record: user's record
-        :type record:dict
-        :return: lower_first_name and lower_last_name if they were found
-        in the user's record. Return None, none otherwise.
+        :type record: dict
+        :returns: lower_first_name and lower_last_name if they were found
+            in the user's record. Return None, none otherwise.
         :rtype: string, string or None, None.
 
         """
@@ -161,16 +187,19 @@ class LoginPassword():
     @staticmethod
     def extract_name_from_email(record):
         """
+
         When there is no valid first name and last name in the record,
         the email is used to generate the login. Here, we assume the email
         is firstname.lastname@something.smthg. The first name and last names
         are extracted from the email, special charcaters are removed and
         they are changed into lower case.
+
         :param record: user's data
-        :type record:dict
-        :return: the first name and last name taken from the user's email.
-        lower_first_name, lower_last_name.
+        :type record: dict
+        :returns: the first name and last name taken from the user's email.
+            lower_first_name, lower_last_name.
         :rtype: string, string
+
         """
 
         email = record['email']
@@ -196,13 +225,18 @@ class LoginPassword():
         return lower_first_name, lower_last_name
 
     def get_user_firstname_lastname(self, record):
-        """Get the user first name and last name from the information
-        we have in the record.
+        """
+
+        Get the user first name and last name from the information we have in
+        the record.
+
         :param record: user's information
         :type record: dict
-        :return: the user's first name and last name.
-        ..seealso: clean_user_names
-        ..seealso: extract_name_from_email
+        :returns: the user's first name and last name.
+
+        .. seealso:: clean_user_names
+        .. seealso:: extract_name_from_email
+
         """
         lower_first_name, lower_last_name = self.clean_user_names(record)
 
@@ -210,62 +244,64 @@ class LoginPassword():
         if lower_first_name is None and lower_last_name is None:
 
             lower_first_name, lower_last_name = \
-                            self.extract_name_from_email(record)
+                self.extract_name_from_email(record)
 
         return lower_first_name, lower_last_name
 
-
     def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
         """
-        Algorithm to select sets of characters from the first name and
-        last name, depending on the lenght of the last name and the
-        maximum login length which in our case is set to 8 charachetrs.
+
+        Algorithm to select sets of characters from the first name and last
+        name, depending on the lenght of the last name and the maximum login
+        length which in our case is set to 8 characters.
+
         :param lower_first_name: user's first name in lower case.
         :param lower_last_name: usr's last name in lower case.
-        :return: user's login
-        :rtype:string
+        :returns: user's login
+        :rtype: string
+
         """
         length_last_name = len(lower_last_name)
         self.login_max_length = 8
 
         #Try generating a unique login based on first name and last name
 
-        if length_last_name >= self.login_max_length :
+        if length_last_name >= self.login_max_length:
             login = lower_last_name[0:self.login_max_length]
             index = 0
-            logger.debug("login : %s index : %s" %(login, index))
-        elif length_last_name >= 4 :
+            logger.debug("login : %s index : %s" % (login, index))
+        elif length_last_name >= 4:
             login = lower_last_name
             index = 0
-            logger.debug("login : %s index : %s" %(login, index))
-        elif length_last_name == 3 :
+            logger.debug("login : %s index : %s" % (login, index))
+        elif length_last_name == 3:
             login = lower_first_name[0:1] + lower_last_name
             index = 1
-            logger.debug("login : %s index : %s" %(login, index))
+            logger.debug("login : %s index : %s" % (login, index))
         elif length_last_name == 2:
-            if len ( lower_first_name) >=2:
+            if len(lower_first_name) >= 2:
                 login = lower_first_name[0:2] + lower_last_name
                 index = 2
-                logger.debug("login : %s index : %s" %(login, index))
+                logger.debug("login : %s index : %s" % (login, index))
             else:
                 logger.error("LoginException : \
                             Generation login error with \
                             minimum four characters")
 
-        else :
+        else:
             logger.error("LDAP LdapGenerateUniqueLogin failed : \
-                            impossible to generate unique login for %s %s" \
-                            %(lower_first_name,lower_last_name))
+                        impossible to generate unique login for %s %s"
+                         % (lower_first_name, lower_last_name))
         return index, login
 
-
-
     def generate_password(self):
+        """
 
-        """Generate a password upon  adding a new user in LDAP Directory
-        (8 characters length). The generated password is composed  of characters
-        from the charsPassword list
-        :return: the randomly generated password
+        Generate a password upon  adding a new user in LDAP Directory
+        (8 characters length). The generated password is composed of characters
+        from the chars_password list.
+
+        :returns: the randomly generated password
         :rtype: string
 
         """
@@ -273,27 +309,33 @@ class LoginPassword():
 
         length = len(self.chars_password)
         for index in range(self.length_password):
-            char_index = random.randint(0, length-1)
+            char_index = random.randint(0, length - 1)
             password += self.chars_password[char_index]
 
         return password
 
     @staticmethod
     def encrypt_password(password):
-        """ Use passlib library to make a RFC2307 LDAP encrypted password
-        salt size = 8, use sha-1 algorithm.
+        """
+
+        Use passlib library to make a RFC2307 LDAP encrypted password salt size
+        is 8, use sha-1 algorithm.
+
         :param password:  password not encrypted.
         :type password: string
-        :return: Returns encrypted password.
-        :rtype:string
+        :returns: Returns encrypted password.
+        :rtype: string
+
         """
         #Keep consistency with Java Iotlab's LDAP API
         #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
-        return lssha.encrypt(password, salt_size = 8)
+        return lssha.encrypt(password, salt_size=8)
 
 
+class LDAPapi:
+    """Defines functions to insert and search entries in the LDAP.
 
-class LDAPapi :
+    """
     def __init__(self):
         logger.setLevelDebug()
 
@@ -302,24 +344,17 @@ class LDAPapi :
         config = Config()
         self.login_pwd = LoginPassword()
         self.authname = config.SFA_REGISTRY_ROOT_AUTH
-
         self.conn =  ldap_co()
         self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
         self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
         self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
         self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
-
         self.baseDN = self.conn.ldapPeopleDN
-
-
-
         self.ldapShell = '/bin/bash'
 
 
-
     def LdapGenerateUniqueLogin(self, record):
         """
-<<<<<<< HEAD:sfa/iotlab/LDAPapi.py
 
         Generate login for adding a new user in LDAP Directory
         (four characters minimum length). Get proper last name and
@@ -327,8 +362,8 @@ class LDAPapi :
 
         :param record: Record must contain first_name and last_name.
         :param record: dict
-        :return: the generated login for the user described with record if the
-        login generation is successful, None if it fails.
+        :returns: the generated login for the user described with record if the
+            login generation is successful, None if it fails.
         :rtype: string or None
 
         """
@@ -337,18 +372,17 @@ class LDAPapi :
             record['email'] = record['mail']
 
         lower_first_name, lower_last_name =  \
-                        self.login_pwd.get_user_firstname_lastname(record)
+            self.login_pwd.get_user_firstname_lastname(record)
 
+        index, login = self.login_pwd.choose_sets_chars_for_login(
+            lower_first_name, lower_last_name)
 
-        index, login = self.login_pwd.choose_sets_chars_for_login( \
-                                                            lower_first_name, \
-                                                            lower_last_name)
         login_filter = '(uid=' + login + ')'
         get_attrs = ['uid']
-        try :
+        try:
             #Check if login already in use
 
-            while (len(self.LdapSearch(login_filter, get_attrs)) is not 0 ):
+            while (len(self.LdapSearch(login_filter, get_attrs)) is not 0):
 
                 index += 1
                 if index >= 9:
@@ -357,26 +391,30 @@ class LDAPapi :
                 else:
                     try:
                         login = \
-                                lower_first_name[0:index] + \
-                        lower_last_name[0:self.login_pwd.login_max_length-index]
-                        login_filter = '(uid='+ login+ ')'
+                            lower_first_name[0:index] + \
+                            lower_last_name[0:
+                                            self.login_pwd.login_max_length
+                                            - index]
+                        login_filter = '(uid=' + login + ')'
                     except KeyError:
                         print "lower_first_name - lower_last_name too short"
 
-            logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s"%(login))
+            logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s"
+                         % (login))
             return login
 
-        except  ldap.LDAPError, error :
-            logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" %error)
+        except ldap.LDAPError, error:
+            logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" % (error))
             return None
 
-
     def find_max_uidNumber(self):
+        """Find the LDAP max uidNumber (POSIX uid attribute).
 
-        """Find the LDAP max uidNumber (POSIX uid attribute) .
         Used when adding a new user in LDAP Directory
-        :return: max uidNumber + 1
-        :rtype:string
+
+        :returns: max uidNumber + 1
+        :rtype: string
+
         """
         #First, get all the users in the LDAP
         get_attrs = "(uidNumber=*)"
@@ -388,10 +426,9 @@ class LDAPapi :
             max_uidnumber = self.ldapUserUidNumberMin
         #Otherwise, get the highest uidNumber
         else:
-
-            uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
+            uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data]
             logger.debug("LDAPapi.py \tfind_max_uidNumber  \
-                                    uidNumberList %s " %(uidNumberList))
+                            uidNumberList %s " % (uidNumberList))
             max_uidnumber = max(uidNumberList) + 1
 
         return str(max_uidnumber)
@@ -407,29 +444,31 @@ class LDAPapi :
     @staticmethod
     #TODO Handle OR filtering in the ldap query when
     #dealing with a list of records instead of doing a for loop in GetPersons
-    def make_ldap_filters_from_record( record=None):
-        """
-        Helper function to make LDAP filter requests out of SFA records.
+    def make_ldap_filters_from_record(record=None):
+        """Helper function to make LDAP filter requests out of SFA records.
+
         :param record: user's sfa record. Should contain first_name,last_name,
-        email or mail, and if the record is enabled or not. If the dict
-        record does not have all of these, must at least contain the user's
-        email.
+            email or mail, and if the record is enabled or not. If the dict
+            record does not have all of these, must at least contain the user's
+            email.
         :type record: dict
-        :return: LDAP request
+        :returns: LDAP request
         :rtype: string
+
         """
         req_ldap = ''
         req_ldapdict = {}
         if record :
-            if 'first_name' in record  and 'last_name' in record:
-                req_ldapdict['cn'] = str(record['first_name'])+" "\
-                                        + str(record['last_name'])
-            if 'email' in record :
+            if 'first_name' in record and 'last_name' in record:
+                if record['first_name'] != record['last_name']:
+                    req_ldapdict['cn'] = str(record['first_name'])+" "\
+                        + str(record['last_name'])
+            if 'email' in record:
                 req_ldapdict['mail'] = record['email']
             if 'mail' in record:
                 req_ldapdict['mail'] = record['mail']
             if 'enabled' in record:
-                if record['enabled'] == True :
+                if record['enabled'] is True:
                     req_ldapdict['shadowExpire'] = '-1'
                 else:
                     req_ldapdict['shadowExpire'] = '0'
@@ -440,45 +479,42 @@ class LDAPapi :
             #Plus, the SFA user may already have an account with iotlab
             #using another login.
 
-
-
             logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
-                                record %s req_ldapdict %s" \
-                                %(record, req_ldapdict))
+                                record %s req_ldapdict %s"
+                         (record, req_ldapdict))
 
             for k in req_ldapdict:
-                req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
-            if  len(req_ldapdict.keys()) >1 :
+                req_ldap += '(' + str(k) + '=' + str(req_ldapdict[k]) + ')'
+            if len(req_ldapdict.keys()) >1 :
                 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
                 size = len(req_ldap)
-                req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
+                req_ldap = req_ldap[:(size-1)] + ')' + req_ldap[(size-1):]
         else:
             req_ldap = "(cn=*)"
 
         return req_ldap
 
     def make_ldap_attributes_from_record(self, record):
-        """When adding a new user to Iotlab's LDAP, creates an attributes
-        dictionnary from the SFA record understandable by LDAP.
-        Generates the user's LDAP login.
-        User is automatically validated (account enabled) and described
-        as a SFA USER FROM OUTSIDE SENSLAB'.
+        """
+
+        When adding a new user to Iotlab's LDAP, creates an attributes
+        dictionnary from the SFA record understandable by LDAP. Generates the
+        user's LDAP login.User is automatically validated (account enabled)
+        and described as a SFA USER FROM OUTSIDE IOTLAB.
+
         :param record: must contain the following keys and values:
-        first_name, last_name, mail, pkey (ssh key).
+            first_name, last_name, mail, pkey (ssh key).
         :type record: dict
-
-        :return: dictionary of attributes using LDAP data structure
-        model.
+        :returns: dictionary of attributes using LDAP data structure model.
         :rtype: dict
 
         """
 
         attrs = {}
-        attrs['objectClass'] = ["top", "person", "inetOrgPerson", \
-                                    "organizationalPerson", "posixAccount", \
-                                    "shadowAccount", "systemQuotas", \
-                                    "ldapPublicKey"]
-
+        attrs['objectClass'] = ["top", "person", "inetOrgPerson",
+                                "organizationalPerson", "posixAccount",
+                                "shadowAccount", "systemQuotas",
+                                "ldapPublicKey"]
 
         attrs['uid'] = self.LdapGenerateUniqueLogin(record)
         try:
@@ -493,7 +529,6 @@ class LDAPapi :
             attrs['cn'] = attrs['uid']
             attrs['gecos'] = attrs['uid']
 
-
         attrs['quota'] = self.ldapUserQuotaNFS
         attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
         attrs['loginShell'] = self.ldapShell
@@ -533,28 +568,27 @@ class LDAPapi :
 
     def LdapAddUser(self, record) :
         """Add SFA user to LDAP if it is not in LDAP  yet.
-        :param record: dictionnary with the user's data.
 
-        :return: a dictionary with the status (Fail= False, Success= True)
-        and the uid of the newly added user if successful, or the error
-        meassage it is not. Dict has keys bool and message in case of failure,
-        and bool uid in case of success.
+        :param record: dictionnary with the user's data.
+        :returns: a dictionary with the status (Fail= False, Success= True)
+            and the uid of the newly added user if successful, or the error
+            meassage it is not. Dict has keys bool and message in case of
+            failure, and bool uid in case of success.
         :rtype: dict
 
-        ..seealso: make_ldap_filters_from_record
+        .. seealso:: make_ldap_filters_from_record
 
         """
         logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
         user_ldap_attrs = self.make_ldap_attributes_from_record(record)
 
-
         #Check if user already in LDAP wih email, first name and last name
         filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
         user_exist = self.LdapSearch(filter_by)
         if user_exist:
             logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
-                        already exists" %(user_ldap_attrs['sn'], \
-                        user_ldap_attrs['mail']))
+                        already exists" % (user_ldap_attrs['sn'],
+                           user_ldap_attrs['mail']))
             return {'bool': False}
 
         #Bind to the server
@@ -563,40 +597,38 @@ class LDAPapi :
         if(result['bool']):
 
             # A dict to help build the "body" of the object
-
-            logger.debug(" \r\n \t LDAP LdapAddUser attrs %s " %user_ldap_attrs)
+            logger.debug(" \r\n \t LDAP LdapAddUser attrs %s "
+                         % user_ldap_attrs)
 
             # The dn of our new entry/object
             dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
 
             try:
                 ldif = modlist.addModlist(user_ldap_attrs)
-                logger.debug("LDAPapi.py add attrs %s \r\n  ldif %s"\
-                                %(user_ldap_attrs, ldif) )
+                logger.debug("LDAPapi.py add attrs %s \r\n  ldif %s"
+                             % (user_ldap_attrs, ldif))
                 self.conn.ldapserv.add_s(dn, ldif)
 
-                logger.info("Adding user %s login %s in LDAP" \
-                        %(user_ldap_attrs['cn'] , user_ldap_attrs['uid']))
-
-
+                logger.info("Adding user %s login %s in LDAP"
+                            % (user_ldap_attrs['cn'], user_ldap_attrs['uid']))
             except ldap.LDAPError, error:
-                logger.log_exc("LDAP Add Error %s" %error)
+                logger.log_exc("LDAP Add Error %s" % error)
                 return {'bool': False, 'message': error}
 
             self.conn.close()
-            return {'bool': True, 'uid':user_ldap_attrs['uid']}
+            return {'bool': True, 'uid': user_ldap_attrs['uid']}
         else:
             return result
 
-
     def LdapDelete(self, person_dn):
-        """
-        Deletes a person in LDAP. Uses the dn of the user.
+        """Deletes a person in LDAP. Uses the dn of the user.
+
         :param person_dn: user's ldap dn.
         :type person_dn: string
-        :return: dictionary with bool True if successful, bool False
-        and the error if not.
-        :rtype:dict
+        :returns: dictionary with bool True if successful, bool False
+            and the error if not.
+        :rtype: dict
+
         """
         #Connect and bind
         result =  self.conn.connect()
@@ -607,26 +639,27 @@ class LDAPapi :
                 return {'bool': True}
 
             except ldap.LDAPError, error:
-                logger.log_exc("LDAP Delete Error %s" %error)
+                logger.log_exc("LDAP Delete Error %s" % error)
                 return {'bool': False, 'message': error}
 
-
     def LdapDeleteUser(self, record_filter):
-        """
-        Deletes a SFA person in LDAP, based on the user's hrn.
+        """Deletes a SFA person in LDAP, based on the user's hrn.
+
         :param record_filter: Filter to find the user to be deleted. Must
-        contain at least the user's email.
+            contain at least the user's email.
         :type record_filter: dict
-        :return: dict with bool True if successful, bool False and error message
-        otherwise
-        :rtype:dict
-        ..seealso: LdapFindUser docstring for more info on record filter.
-        ..seealso: LdapDelete for user deletion
+        :returns: dict with bool True if successful, bool False and error
+            message otherwise.
+        :rtype: dict
+
+        .. seealso:: LdapFindUser docstring for more info on record filter.
+        .. seealso:: LdapDelete for user deletion
+
         """
         #Find uid of the  person
         person = self.LdapFindUser(record_filter, [])
-        logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s" \
-        %(record_filter, person))
+        logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s"
+                     % (record_filter, person))
 
         if person:
             dn = 'uid=' + person['uid'] + "," + self.baseDN
@@ -636,20 +669,21 @@ class LDAPapi :
         result = self.LdapDelete(dn)
         return result
 
-
     def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
         """ Modifies a LDAP entry, replaces user's old attributes with
         the new ones given.
+
         :param dn: user's absolute name  in the LDAP hierarchy.
         :param old_attributes_dict: old user's attributes. Keys must match
-        the ones used in the LDAP model.
+            the ones used in the LDAP model.
         :param new_attributes_dict: new user's attributes. Keys must match
-        the ones used in the LDAP model.
+            the ones used in the LDAP model.
         :type dn: string
         :type old_attributes_dict: dict
         :type new_attributes_dict: dict
-        :return: dict bool True if Successful, bool False if not.
-        :rtype:dict
+        :returns: dict bool True if Successful, bool False if not.
+        :rtype: dict
+
         """
 
         ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
@@ -659,28 +693,32 @@ class LDAPapi :
             try:
                 self.conn.ldapserv.modify_s(dn, ldif)
                 self.conn.close()
-                return {'bool' : True }
+                return {'bool': True}
             except ldap.LDAPError, error:
-                logger.log_exc("LDAP LdapModify Error %s" %error)
-                return {'bool' : False }
+                logger.log_exc("LDAP LdapModify Error %s" % error)
+                return {'bool': False}
 
 
     def LdapModifyUser(self, user_record, new_attributes_dict):
         """
-        Gets the record from one user based on the user sfa record
-        and changes the attributes according to the specified new_attributes.
-        Do not use this if we need to modify the uid. Use a ModRDN
-        #operation instead ( modify relative DN )
+
+        Gets the record from one user based on the user sfa recordand changes
+        the attributes according to the specified new_attributes. Do not use
+        this if we need to modify the uid. Use a ModRDN operation instead
+        ( modify relative DN ).
+
         :param user_record: sfa user record.
         :param new_attributes_dict: new user attributes, keys must be the
-        same as the LDAP model.
+            same as the LDAP model.
         :type user_record: dict
         :type new_attributes_dict: dict
-        :return: bool True if successful, bool False if not.
+        :returns: bool True if successful, bool False if not.
         :rtype: dict
-        ..seealso: make_ldap_filters_from_record for info on what is mandatory
-        in the user_record.
-        ..seealso: make_ldap_attributes_from_record for the LDAP objectclass.
+
+        .. seealso:: make_ldap_filters_from_record for info on what is mandatory
+            in the user_record.
+        .. seealso:: make_ldap_attributes_from_record for the LDAP objectclass.
+
         """
         if user_record is None:
             logger.error("LDAP \t LdapModifyUser Need user record  ")
@@ -690,30 +728,31 @@ class LDAPapi :
         #person = self.LdapFindUser(record_filter,[])
         req_ldap = self.make_ldap_filters_from_record(user_record)
         person_list = self.LdapSearch(req_ldap, [])
-        logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s" \
-                                                        %(person_list))
-        if person_list and len(person_list) > 1 :
+        logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s"
+                     % (person_list))
+
+        if person_list and len(person_list) > 1:
             logger.error("LDAP \t LdapModifyUser Too many users returned")
             return {'bool': False}
-        if person_list is None :
-            logger.error("LDAP \t LdapModifyUser  User %s doesn't exist "\
-                        %(user_record))
+        if person_list is None:
+            logger.error("LDAP \t LdapModifyUser  User %s doesn't exist "
+                         % (user_record))
             return {'bool': False}
 
         # The dn of our existing entry/object
         #One result only from ldapSearch
         person = person_list[0][1]
-        dn  = 'uid=' + person['uid'][0] + "," + self.baseDN
+        dn = 'uid=' + person['uid'][0] + "," + self.baseDN
 
         if new_attributes_dict:
             old = {}
             for k in new_attributes_dict:
                 if k not in person:
-                    old[k] =  ''
-                else :
+                    old[k] = ''
+                else:
                     old[k] = person[k]
-            logger.debug(" LDAPapi.py \t LdapModifyUser  new_attributes %s"\
-                                %( new_attributes_dict))
+            logger.debug(" LDAPapi.py \t LdapModifyUser  new_attributes %s"
+                         % (new_attributes_dict))
             result = self.LdapModify(dn, old, new_attributes_dict)
             return result
         else:
@@ -721,17 +760,21 @@ class LDAPapi :
             return {'bool': False}
 
 
-
-
     def LdapMarkUserAsDeleted(self, record):
         """
-        Sets shadowExpire to 0, disabling the user in LDAP.
-        Calls LdapModifyUser to change the shadowExpire of the user.
+
+        Sets shadowExpire to 0, disabling the user in LDAP. Calls LdapModifyUser
+        to change the shadowExpire of the user.
+
         :param record: the record of the user who has to be disabled.
+            Should contain first_name,last_name, email or mail, and if the
+            record is enabled or not. If the dict record does not have all of
+            these, must at least contain the user's email.
         :type record: dict
-        :return:  bool True if successful or bool False if not
-        :rtype:dict
-        ..seealso: LdapModifyUser
+        :returns: {bool: True} if successful or {bool: False} if not
+        :rtype: dict
+
+        .. seealso:: LdapModifyUser, make_ldap_attributes_from_record
         """
 
         new_attrs = {}
@@ -741,40 +784,58 @@ class LDAPapi :
         ret = self.LdapModifyUser(record, new_attrs)
         return ret
 
-
     def LdapResetPassword(self, record):
-        """
-        Resets password for the user whose record is the parameter and changes
-        the corresponding entry in the LDAP.
+        """Resets password for the user whose record is the parameter and
+        changes the corresponding entry in the LDAP.
+
+        :param record: user's sfa record whose Ldap password must be reset.
+            Should contain first_name,last_name,
+            email or mail, and if the record is enabled or not. If the dict
+            record does not have all of these, must at least contain the user's
+            email.
+        :type record: dict
+        :returns: return value of LdapModifyUser. True if successful, False
+            otherwise.
+
+        .. seealso:: LdapModifyUser, make_ldap_attributes_from_record
 
         """
         password = self.login_pwd.generate_password()
         attrs = {}
         attrs['userPassword'] = self.login_pwd.encrypt_password(password)
-        logger.debug("LDAP LdapResetPassword encrypt_password %s"\
-                    %(attrs['userPassword']))
+        logger.debug("LDAP LdapResetPassword encrypt_password %s"
+                     % (attrs['userPassword']))
         result = self.LdapModifyUser(record, attrs)
         return result
 
 
-    def LdapSearch (self, req_ldap = None, expected_fields = None ):
+    def LdapSearch(self, req_ldap=None, expected_fields=None):
         """
-        Used to search directly in LDAP, by using ldap filters and
-        return fields.
-        When req_ldap is None, returns all the entries in the LDAP.
+        Used to search directly in LDAP, by using ldap filters and return
+        fields. When req_ldap is None, returns all the entries in the LDAP.
+
+        :param req_ldap: ldap style request, with appropriate filters,
+             example: (cn=*).
+        :param expected_fields: Fields in the user ldap entry that has to be
+            returned. If None is provided, will return 'mail', 'givenName',
+            'sn', 'uid', 'sshPublicKey', 'shadowExpire'.
+        :type req_ldap: string
+        :type expected_fields: list
+
+        .. seealso:: make_ldap_filters_from_record for req_ldap format.
 
         """
-        result = self.conn.connect(bind = False)
-        if (result['bool']) :
+        result = self.conn.connect(bind=False)
+        if (result['bool']):
 
             return_fields_list = []
-            if expected_fields == None :
-                return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
-                                        'sshPublicKey', 'shadowExpire']
-            else :
+            if expected_fields is None:
+                return_fields_list = ['mail', 'givenName', 'sn', 'uid',
+                                      'sshPublicKey', 'shadowExpire']
+            else:
                 return_fields_list = expected_fields
             #No specifc request specified, get the whole LDAP
-            if req_ldap == None:
+            if req_ldap is None:
                 req_ldap = '(cn=*)'
 
             logger.debug("LDAP.PY \t LdapSearch  req_ldap %s \
@@ -783,43 +844,44 @@ class LDAPapi :
 
             try:
                 msg_id = self.conn.ldapserv.search(
-                                            self.baseDN,ldap.SCOPE_SUBTREE,\
-                                            req_ldap, return_fields_list)
+                    self.baseDN, ldap.SCOPE_SUBTREE,
+                    req_ldap, return_fields_list)
                 #Get all the results matching the search from ldap in one
                 #shot (1 value)
                 result_type, result_data = \
-                                        self.conn.ldapserv.result(msg_id, 1)
+                    self.conn.ldapserv.result(msg_id, 1)
 
                 self.conn.close()
 
-                logger.debug("LDAP.PY \t LdapSearch  result_data %s"\
-                            %(result_data))
+                logger.debug("LDAP.PY \t LdapSearch  result_data %s"
+                             % (result_data))
 
                 return result_data
 
-            except  ldap.LDAPError, error :
-                logger.log_exc("LDAP LdapSearch Error %s" %error)
+            except ldap.LDAPError, error:
+                logger.log_exc("LDAP LdapSearch Error %s" % error)
                 return []
 
             else:
-                logger.error("LDAP.PY \t Connection Failed" )
+                logger.error("LDAP.PY \t Connection Failed")
                 return
 
-
     def _process_ldap_info_for_all_users(self, result_data):
-        """
-        Process the data of all enabled users in LDAP.
+        """Process the data of all enabled users in LDAP.
+
         :param result_data: Contains information of all enabled users in LDAP
-        and is coming from LdapSearch.
+            and is coming from LdapSearch.
         :param result_data: list
-        ..seealso: LdapSearch
+
+        .. seealso:: LdapSearch
+
         """
         results = []
-        logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s " \
-                            %(result_data))
+        logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s "
+                     (result_data))
         for ldapentry in result_data:
-            logger.debug(" LDAP.py _process_ldap_info_for_all_users ldapentry name : %s " \
-                            %(ldapentry[1]['uid'][0]))
+            logger.debug(" LDAP.py _process_ldap_info_for_all_users \
+                        ldapentry name : %s " % (ldapentry[1]['uid'][0]))
             tmpname = ldapentry[1]['uid'][0]
             hrn = self.authname + "." + tmpname
 
@@ -827,48 +889,50 @@ class LDAPapi :
             if ldapentry[1]['mail'][0] == "unknown":
                 tmpemail = None
 
-
             try:
-                results.append(  {
-                        'type': 'user',
-                        'pkey': ldapentry[1]['sshPublicKey'][0],
-                        #'uid': ldapentry[1]['uid'][0],
-                        'uid': tmpname ,
-                        'email':tmpemail,
-                        #'email': ldapentry[1]['mail'][0],
-                        'first_name': ldapentry[1]['givenName'][0],
-                        'last_name': ldapentry[1]['sn'][0],
-                        #'phone': 'none',
-                        'serial': 'none',
-                        'authority': self.authname,
-                        'peer_authority': '',
-                        'pointer' : -1,
-                        'hrn': hrn,
-                        )
+                results.append({
+                    'type': 'user',
+                    'pkey': ldapentry[1]['sshPublicKey'][0],
+                    #'uid': ldapentry[1]['uid'][0],
+                    'uid': tmpname ,
+                    'email':tmpemail,
+                    #'email': ldapentry[1]['mail'][0],
+                    'first_name': ldapentry[1]['givenName'][0],
+                    'last_name': ldapentry[1]['sn'][0],
+                    #'phone': 'none',
+                    'serial': 'none',
+                    'authority': self.authname,
+                    'peer_authority': '',
+                    'pointer': -1,
+                    'hrn': hrn,
+                              })
             except KeyError, error:
-                logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s" \
-                                            %(error))
+                logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s"
+                               (error))
                 return
 
         return results
 
     def _process_ldap_info_for_one_user(self, record, result_data):
         """
+
         Put the user's ldap data into shape. Only deals with one user
         record and one user data from ldap.
+
         :param record: user record
         :param result_data: Raw ldap data coming from LdapSearch
-        :return: user's data dict with 'type','pkey','uid', 'email',
-        'first_name' 'last_name''serial''authority''peer_authority'
-        'pointer''hrn'
+        :returns: user's data dict with 'type','pkey','uid', 'email',
+            'first_name' 'last_name''serial''authority''peer_authority'
+            'pointer''hrn'
         :type record: dict
         :type result_data: list
         :rtype :dict
+
         """
         #One entry only in the ldap data because we used a  filter
         #to find one user only
         ldapentry = result_data[0][1]
-        logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" %(ldapentry))
+        logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" % (ldapentry))
         tmpname = ldapentry['uid'][0]
 
         tmpemail = ldapentry['mail'][0]
@@ -891,42 +955,42 @@ class LDAPapi :
         else:
             hrn = None
 
-
-
-        results =  {
-                    'type': 'user',
-                    'pkey': ldapentry['sshPublicKey'],
-                    #'uid': ldapentry[1]['uid'][0],
-                    'uid': tmpname ,
-                    'email':tmpemail,
-                    #'email': ldapentry[1]['mail'][0],
-                    'first_name': ldapentry['givenName'][0],
-                    'last_name': ldapentry['sn'][0],
-                    #'phone': 'none',
-                    'serial': 'none',
-                    'authority': parent_hrn,
-                    'peer_authority': peer_authority,
-                    'pointer' : -1,
-                    'hrn': hrn,
+        results = {
+            'type': 'user',
+            'pkey': ldapentry['sshPublicKey'],
+            #'uid': ldapentry[1]['uid'][0],
+            'uid': tmpname,
+            'email': tmpemail,
+            #'email': ldapentry[1]['mail'][0],
+            'first_name': ldapentry['givenName'][0],
+            'last_name': ldapentry['sn'][0],
+            #'phone': 'none',
+            'serial': 'none',
+            'authority': parent_hrn,
+            'peer_authority': peer_authority,
+            'pointer': -1,
+            'hrn': hrn,
                     }
         return results
 
-
     def LdapFindUser(self, record=None, is_user_enabled=None,
                      expected_fields=None):
         """
+
         Search a SFA user with a hrn. User should be already registered
         in Iotlab LDAP.
+
         :param record: sfa user's record. Should contain first_name,last_name,
-        email or mail. If no record is provided, returns all the users found
-        in LDAP.
+            email or mail. If no record is provided, returns all the users found
+            in LDAP.
         :type record: dict
         :param is_user_enabled: is the user's iotlab account already valid.
         :type is_user_enabled: Boolean.
-        :return: LDAP entries from ldap matching the filter provided. Returns
-        a single entry if one filter has been given and a list of
-        entries otherwise.
+        :returns: LDAP entries from ldap matching the filter provided. Returns
+            a single entry if one filter has been given and a list of
+            entries otherwise.
         :rtype:  dict or list
+
         """
         custom_record = {}
         if is_user_enabled:
@@ -934,19 +998,18 @@ class LDAPapi :
         if record:
             custom_record.update(record)
 
-
         req_ldap = self.make_ldap_filters_from_record(custom_record)
         return_fields_list = []
-        if expected_fields == None :
-            return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
-                                    'sshPublicKey']
-        else :
+        if expected_fields is None:
+            return_fields_list = ['mail', 'givenName', 'sn', 'uid',
+                                  'sshPublicKey']
+        else:
             return_fields_list = expected_fields
 
-        result_data = self.LdapSearch(req_ldap, return_fields_list )
-        logger.debug("LDAP.PY \t LdapFindUser  result_data %s" %(result_data))
+        result_data = self.LdapSearch(req_ldap, return_fields_list)
+        logger.debug("LDAP.PY \t LdapFindUser  result_data %s" % (result_data))
 
-        if len(result_data) is 0:
+        if len(result_data) == 0:
             return None
         #Asked for a specific user
         if record is not None:
@@ -955,5 +1018,4 @@ class LDAPapi :
         else:
         #Asked for all users in ldap
             results = self._process_ldap_info_for_all_users(result_data)
-        return results
-
+        return results
\ No newline at end of file