343 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #maj du 08/10/2024 v4
 | |
| from resources.common_imports import *
 | |
| 
 | |
| #les variables globales minimum
 | |
| from resources.config import ldap_admin, ldap_pass, ldap_root, ldap_host
 | |
| 
 | |
| class Ldap_user(Resource):
 | |
|   
 | |
|     def __init__(self):
 | |
|         global ldap_admin, ldap_pass, ldap_root, ldap_host
 | |
|         self.ldap_admin = ldap_admin
 | |
|         self.ldap_pass = ldap_pass
 | |
|         self.ldap_root = ldap_root
 | |
|         self.ldap_host = f"ldap://{ldap_host}"
 | |
| 
 | |
|     def _connect_ldap(self):
 | |
|         ldap_connection = ldap.initialize(self.ldap_host)
 | |
|         ldap_connection.simple_bind_s("cn={},{}".format(self.ldap_admin, self.ldap_root), self.ldap_pass)
 | |
|         return ldap_connection
 | |
|     
 | |
|     @classmethod
 | |
|     def is_valid_field(cls, field):
 | |
|         allowed_fields = ['numeroMembre','mailDeSecours', 'mailEnabled', 'nextcloudEnabled', 'mobilizonEnabled', 'agoraEnabled', 'userPassword', 'identifiantKaz', 'mailAlias', 'quota']
 | |
|         return field in allowed_fields
 | |
| 
 | |
|     @jwt_required()
 | |
|     def get(self, email):
 | |
|         """
 | |
|         Vérifier si un utilisateur avec cet email existe dans le LDAP soit comme mail principal soit comme alias
 | |
|         ---
 | |
|         tags:
 | |
|           - Ldap        
 | |
|         security:
 | |
|           - Bearer: []        
 | |
|         parameters:
 | |
|           - in: path
 | |
|             name: email
 | |
|             type: string
 | |
|             required: true                
 | |
|         responses:
 | |
|             200:
 | |
|                 description: Existe
 | |
|             400:
 | |
|                 description: N'existe pas
 | |
|             401:
 | |
|                 description: oops, email invalide
 | |
|             402:
 | |
|                 description: oops, autre erreur
 | |
|         
 | |
|         """               
 | |
|         try:
 | |
|           
 | |
|             if not validate_email(email):
 | |
|                 return "Adresse e-mail non valide", 400
 | |
|               
 | |
|             ldap_connection = self._connect_ldap()
 | |
| 
 | |
|             #result = ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, "(cn={})".format(email))
 | |
|             
 | |
|             # Créer une chaîne de filtre pour rechercher dans les champs "cn" et "mailAlias"
 | |
|             filter_str = "(|(cn={})(mailAlias={}))".format(email, email)
 | |
|             result = ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, filter_str)
 | |
|   
 | |
|             ldap_connection.unbind_s()
 | |
| 
 | |
|             if result:
 | |
|                 return True, 200
 | |
|             else:
 | |
|                 return False, 400
 | |
|               
 | |
|         except EmailNotValidError as e:
 | |
|             return str(e), 401
 | |
| 
 | |
|         except ldap.LDAPError as e:
 | |
|             return str(e), 402
 | |
| 
 | |
| 
 | |
| #*************************************************
 | |
|     @jwt_required()
 | |
|     def delete(self, email):
 | |
|         """
 | |
|         Supprimer un utilisateur du LDAP par son adresse e-mail
 | |
|         ---
 | |
|         tags:
 | |
|           - Ldap        
 | |
|         security:
 | |
|           - Bearer: []        
 | |
|         parameters:
 | |
|           - in: path
 | |
|             name: email
 | |
|             type: string
 | |
|             required: true                
 | |
|         responses:
 | |
|             200:
 | |
|                 description: Utilisateur supprimé avec succès
 | |
|             404:
 | |
|                 description: Utilisateur non trouvé dans le LDAP
 | |
|             400:
 | |
|                 description: Erreur lors de la suppression de l'utilisateur
 | |
|         """
 | |
|         try:
 | |
|             if not validate_email(email):
 | |
|                 return "Adresse e-mail non valide", 400
 | |
|             
 | |
|             ldap_connection = self._connect_ldap()
 | |
| 
 | |
|             # Recherche de l'utilisateur
 | |
|             result = ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, "(cn={})".format(email))
 | |
|             
 | |
|             if not result:
 | |
|                 return False, 404  # Utilisateur non trouvé
 | |
| 
 | |
|             # Récupération du DN de l'utilisateur
 | |
|             dn = result[0][0]
 | |
|             
 | |
|             # Suppression de l'utilisateur
 | |
|             ldap_connection.delete_s(dn)
 | |
|             ldap_connection.unbind_s()
 | |
| 
 | |
|             return True, 200  # Utilisateur supprimé avec succès
 | |
|               
 | |
|         except ldap.NO_SUCH_OBJECT:
 | |
|             return False, 404  # Utilisateur non trouvé
 | |
|         except ldap.LDAPError as e:
 | |
|             return str(e), 400  # Erreur lors de la suppression
 | |
|         except EmailNotValidError as e:
 | |
|             return str(e), 400
 | |
| 
 | |
| 
 | |
| #*************************************************
 | |
|     @jwt_required()
 | |
|     def post(self, email):
 | |
|         """
 | |
|         Ajouter, supprimer ou modifier un champ pour l'utilisateur LDAP
 | |
|         ---
 | |
|         tags:
 | |
|           - Ldap   
 | |
|         security:
 | |
|           - Bearer: []                
 | |
|         parameters:
 | |
|           - in: path
 | |
|             name: email
 | |
|             type: string
 | |
|             required: true
 | |
|           - in: query
 | |
|             name: action
 | |
|             type: string
 | |
|             required: true
 | |
|             enum: ['add', 'delete', 'modify']
 | |
|           - in: body
 | |
|             name: data
 | |
|             required: true
 | |
|             schema:
 | |
|               type: object
 | |
|               properties:
 | |
|                 field:
 | |
|                   type: string
 | |
|                   enum: ['numeroMembre', 'mailDeSecours', 'mailEnabled', 'nextcloudEnabled', 'mobilizonEnabled', 'agoraEnabled', 'userPassword', 'identifiantKaz', 'mailAlias', 'quota' ]
 | |
|                   description: Le champ à ajouter, supprimer ou modifier (par exemple, mailDeSecours, mailAlias, etc.)
 | |
|                 value:
 | |
|                   type: string        
 | |
|                   description: La valeur à ajouter, supprimer ou modifier pour le champ spécifié
 | |
|         responses:
 | |
|             200:
 | |
|                 description: Opération réussie
 | |
|             404:
 | |
|                 description: Utilisateur non trouvé dans le LDAP
 | |
|             400:
 | |
|                 description: Erreur lors de l'opération
 | |
|         """
 | |
|         
 | |
|         try:
 | |
|             if not validate_email(email):
 | |
|                 return "Adresse e-mail non valide", 400
 | |
|             
 | |
|             action = request.args.get('action')
 | |
|             field = request.json.get('field')
 | |
|             value = request.json.get('value')
 | |
|             
 | |
|             if not action or not field or not value:
 | |
|                 return "Action, champ ou valeur manquant", 400
 | |
|             
 | |
|             if not self.is_valid_field(field):
 | |
|                 return "Champ non autorisé !", 400
 | |
|           
 | |
|             ldap_connection = self._connect_ldap()
 | |
|             result = ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, "(cn={})".format(email))
 | |
|             
 | |
|             if not result:
 | |
|                 return False, 404
 | |
|             
 | |
|             dn = result[0][0]
 | |
| 
 | |
|             if field == 'userPassword' and (action == 'add' or action == 'modify'):
 | |
|                   password_chiffre = sha512_crypt.hash(value)
 | |
|                   value = "{{CRYPT}}{}".format(password_chiffre)
 | |
|                   
 | |
|             if action == 'add':
 | |
|                 mod_attrs = [(ldap.MOD_ADD, field, value.encode('utf-8'))]
 | |
|                 
 | |
|             elif action == 'delete':
 | |
|                 mod_attrs = [(ldap.MOD_DELETE, field, value.encode('utf-8'))]
 | |
|                 
 | |
|             elif action == 'modify':
 | |
| 
 | |
|               if field == 'quota':
 | |
|                   mail_quota_value = value + 'G'
 | |
|                   nextcloud_quota_value = value + " GB"
 | |
|                   mod_attrs = [
 | |
|                       (ldap.MOD_REPLACE, 'quota', value.encode('utf-8')),                    
 | |
|                       (ldap.MOD_REPLACE, 'mailQuota', mail_quota_value.encode('utf-8')),
 | |
|                       (ldap.MOD_REPLACE, 'nextcloudQuota', nextcloud_quota_value.encode('utf-8'))
 | |
|                   ]
 | |
|               else:
 | |
|                   mod_attrs = [(ldap.MOD_REPLACE, field, value.encode('utf-8'))]
 | |
|                               
 | |
|             else:
 | |
|                 return "Action non valide", 400
 | |
|             
 | |
|             ldap_connection.modify_s(dn, mod_attrs)
 | |
|             ldap_connection.unbind_s()
 | |
| 
 | |
|             return True, 200
 | |
|               
 | |
|         except ldap.NO_SUCH_OBJECT:
 | |
|             return False, 404
 | |
|         except ldap.LDAPError as e:
 | |
|             return str(e), 400
 | |
|         except EmailNotValidError as e:
 | |
|             return str(e), 400
 | |
| 
 | |
| #*************************************************
 | |
|     @jwt_required()
 | |
|     def put(self, email, **kwargs):
 | |
|         """
 | |
|         Créer une nouvelle entrée dans le LDAP pour un nouvel utilisateur. QUESTION: A QUOI SERVENT PRENOM/NOM/IDENT_KAZ DANS LE LDAP ? POURQUOI 3 QUOTA ?
 | |
|         ---
 | |
|         tags:
 | |
|           - Ldap    
 | |
|         security:
 | |
|           - Bearer: []                
 | |
|         parameters:
 | |
|           - in: path
 | |
|             name: email
 | |
|             type: string
 | |
|             required: true
 | |
|           - in: body
 | |
|             name: data
 | |
|             required: true
 | |
|             schema:
 | |
|               type: object
 | |
|               properties:
 | |
|                 prenom:
 | |
|                   type: string
 | |
|                   description: Prénom de l'utilisateur
 | |
|                 nom:
 | |
|                   type: string
 | |
|                   description: Nom de l'utilisateur
 | |
|                 password:
 | |
|                   type: string
 | |
|                   description: Mot de passe de l'utilisateur
 | |
|                 email_secours:
 | |
|                   type: string
 | |
|                   description: Adresse e-mail de secours
 | |
|                 quota:
 | |
|                   type: string
 | |
|                   description: Quota de l'utilisateur
 | |
|         responses:
 | |
|             200:
 | |
|                 description: Utilisateur ajouté avec succès
 | |
|             400:
 | |
|                 description: Erreur lors de l'ajout de l'utilisateur
 | |
|             406:
 | |
|                 description: Erreur utilisateur déjà existant
 | |
|         
 | |
|         """
 | |
|         try:
 | |
|                      
 | |
|             if kwargs: # appel depuis une autre api
 | |
|               email_secours = kwargs.get('email_secours')
 | |
|               prenom = kwargs.get('prenom')
 | |
|               nom = kwargs.get('nom')
 | |
|               password = kwargs.get('password')
 | |
|               quota = kwargs.get('quota')
 | |
|               
 | |
|             else: # appel depuis swagger 
 | |
|               email_secours = request.json.get('email_secours')
 | |
|               nom = request.json.get('nom')
 | |
|               prenom = request.json.get('prenom')
 | |
|               password = request.json.get('password')
 | |
|               quota = request.json.get('quota')
 | |
| 
 | |
|             password_chiffre = sha512_crypt.hash(password)
 | |
| 
 | |
|             if not validate_email(email) or not validate_email(email_secours):
 | |
|                 return "Adresse e-mail ou secours non valide", 400
 | |
|             
 | |
|             #le user existe t-il déjà ?
 | |
|             ldap_connection = self._connect_ldap()
 | |
|             result = ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, "(cn={})".format(email))
 | |
|             
 | |
|             if result:
 | |
|                 return "User déjà existant", 406
 | |
| 
 | |
|             # Construire le DN
 | |
|             dn = f"cn={email},ou=users,{ldap_root}"
 | |
|             
 | |
|             mod_attrs = [
 | |
|               ('objectClass', [b'inetOrgPerson', b'PostfixBookMailAccount', b'nextcloudAccount', b'kaznaute']),
 | |
|               ('sn', f'{prenom} {nom}'.encode('utf-8')),
 | |
|               ('mail', email.encode('utf-8')),
 | |
|               ('mailEnabled', b'TRUE'),
 | |
|               ('mailGidNumber', b'5000'),
 | |
|               ('mailHomeDirectory', f"/var/mail/{email.split('@')[1]}/{email.split('@')[0]}/".encode('utf-8')),
 | |
|               ('mailQuota', f'{quota}G'.encode('utf-8')),
 | |
|               ('mailStorageDirectory', f"maildir:/var/mail/{email.split('@')[1]}/{email.split('@')[0]}/".encode('utf-8')),
 | |
|               ('mailUidNumber', b'5000'),
 | |
|               ('mailDeSecours', email_secours.encode('utf-8')),
 | |
|               ('identifiantKaz', f'{prenom.lower()}.{nom.lower()}'.encode('utf-8')),
 | |
|               ('quota', str(quota).encode('utf-8')),
 | |
|               ('nextcloudEnabled', b'TRUE'),
 | |
|               ('nextcloudQuota', f'{quota} GB'.encode('utf-8')),
 | |
|               ('mobilizonEnabled', b'TRUE'),
 | |
|               ('agoraEnabled', b'TRUE'),
 | |
|               ('userPassword', f'{{CRYPT}}{password_chiffre}'.encode('utf-8')),
 | |
|               ('cn', email.encode('utf-8'))            
 | |
|             ]
 | |
|             
 | |
|             ldap_connection.add_s(dn, mod_attrs)
 | |
|             ldap_connection.unbind_s()
 | |
|             
 | |
|             return "Utilisateur créé dans le ldap", 200
 | |
|           
 | |
|         except ldap.LDAPError as e:
 | |
|             return str(e), 400
 | |
|         except EmailNotValidError as e:
 | |
|             return str(e), 400
 | |
| 
 | |
| #*************************************************
 | |
|           
 | |
| 
 | |
|  
 |