KazV2/dockers/apikaz/source/resources/ldap.py

342 lines
12 KiB
Python

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
#*************************************************