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 = ['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: ['mailDeSecours', 'mailEnabled', 'nextcloudEnabled', 'mobilizonEnabled', 'agoraEnabled', 'userPassword', 'identifiantKaz', 'mailAlias', 'quota', 'numeroMembre'] 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 #*************************************************