Quelques améliorations, mise en place de fonctions pour tester parenté,
tester si c'est soi-même qu'on modifie, pour tester si on peut bien altérer l'objet concerné. Création des objets en deux temps (on crée l'objet Crans, puis on l'enregistre dans ldap après test des droits. Changement de méthode de binding : le binding nominatif va être bien trop complexe à implémenter, on va donc faire autrement...
This commit is contained in:
parent
fcafdbff28
commit
42c48f77e8
3 changed files with 190 additions and 61 deletions
13
attributs.py
13
attributs.py
|
@ -425,6 +425,8 @@ class hostAlias(host):
|
||||||
optional = True
|
optional = True
|
||||||
legend = u'Alias de nom de machine'
|
legend = u'Alias de nom de machine'
|
||||||
|
|
||||||
|
can_modify = [nounou, cableur]
|
||||||
|
|
||||||
class macAddress(Attr):
|
class macAddress(Attr):
|
||||||
singlevalue = True
|
singlevalue = True
|
||||||
optional = False
|
optional = False
|
||||||
|
@ -447,6 +449,7 @@ class ipHostNumber(Attr):
|
||||||
legend = u"Adresse IPv4 de la machine"
|
legend = u"Adresse IPv4 de la machine"
|
||||||
hname = "IPv4"
|
hname = "IPv4"
|
||||||
category = 'base_tech'
|
category = 'base_tech'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def parse_value(self, ip, ldif):
|
def parse_value(self, ip, ldif):
|
||||||
if ip == '<automatique>':
|
if ip == '<automatique>':
|
||||||
|
@ -476,6 +479,7 @@ class rid(Attr):
|
||||||
unique = True
|
unique = True
|
||||||
legend = "Identifiant réseau de machine"
|
legend = "Identifiant réseau de machine"
|
||||||
category = 'id'
|
category = 'id'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def parse_value(self, rid, ldif):
|
def parse_value(self, rid, ldif):
|
||||||
self.value = Rid(rid = int(rid))
|
self.value = Rid(rid = int(rid))
|
||||||
|
@ -494,18 +498,21 @@ class puissance(Attr):
|
||||||
optional = True
|
optional = True
|
||||||
legend = u"puissance d'émission pour les bornes wifi"
|
legend = u"puissance d'émission pour les bornes wifi"
|
||||||
category = 'wifi'
|
category = 'wifi'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
class canal(intAttr):
|
class canal(intAttr):
|
||||||
singlevalue = True
|
singlevalue = True
|
||||||
optional = True
|
optional = True
|
||||||
legend = u'Canal d\'émission de la borne'
|
legend = u'Canal d\'émission de la borne'
|
||||||
category = 'wifi'
|
category = 'wifi'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
class portAttr(Attr):
|
class portAttr(Attr):
|
||||||
singlevalue = False
|
singlevalue = False
|
||||||
optional = True
|
optional = True
|
||||||
legend = u'Ouverture de port'
|
legend = u'Ouverture de port'
|
||||||
category = 'firewall'
|
category = 'firewall'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def parse_value(self, port, ldif):
|
def parse_value(self, port, ldif):
|
||||||
if ":" in port:
|
if ":" in port:
|
||||||
|
@ -553,6 +560,7 @@ class prise(Attr):
|
||||||
optional = True
|
optional = True
|
||||||
legend = u"Prise sur laquelle est branchée la machine"
|
legend = u"Prise sur laquelle est branchée la machine"
|
||||||
category = 'base_tech'
|
category = 'base_tech'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def parse_value(self, prise, ldif):
|
def parse_value(self, prise, ldif):
|
||||||
### Tu es une Nounou, je te fais confiance
|
### Tu es une Nounou, je te fais confiance
|
||||||
|
@ -570,6 +578,7 @@ class responsable(Attr):
|
||||||
optional = True
|
optional = True
|
||||||
legend = u"Responsable du club"
|
legend = u"Responsable du club"
|
||||||
category = 'perso'
|
category = 'perso'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def get_respo(self):
|
def get_respo(self):
|
||||||
if self.value == None:
|
if self.value == None:
|
||||||
|
@ -583,12 +592,12 @@ class responsable(Attr):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.__resp
|
return self.__resp
|
||||||
|
|
||||||
|
|
||||||
class blacklist(Attr):
|
class blacklist(Attr):
|
||||||
singlevalue = False
|
singlevalue = False
|
||||||
optional = True
|
optional = True
|
||||||
legend = u"Blackliste"
|
legend = u"Blackliste"
|
||||||
category = 'info'
|
category = 'info'
|
||||||
|
can_modify = [nounou]
|
||||||
|
|
||||||
def parse_value(self, bl, ldif):
|
def parse_value(self, bl, ldif):
|
||||||
bl_debut, bl_fin, bl_type, bl_comm = bl.split('$')
|
bl_debut, bl_fin, bl_type, bl_comm = bl.split('$')
|
||||||
|
@ -712,9 +721,7 @@ class gecos(Attr):
|
||||||
category = 'id'
|
category = 'id'
|
||||||
|
|
||||||
def parse_value(self, gecos, ldif):
|
def parse_value(self, gecos, ldif):
|
||||||
a, b, c, d = gecos.split(',')
|
|
||||||
self.value = gecos
|
self.value = gecos
|
||||||
|
|
||||||
|
|
||||||
class sshFingerprint(Attr):
|
class sshFingerprint(Attr):
|
||||||
singlevalue = False
|
singlevalue = False
|
||||||
|
|
|
@ -77,8 +77,6 @@ def ip6_of_mac(mac, rid):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Rid dans aucune plage: %d" % rid)
|
raise ValueError("Rid dans aucune plage: %d" % rid)
|
||||||
|
|
||||||
print net
|
|
||||||
|
|
||||||
# En théorie, format_mac est inutile, car on ne devrait avoir
|
# En théorie, format_mac est inutile, car on ne devrait avoir
|
||||||
# que des mac formatées.
|
# que des mac formatées.
|
||||||
mac = format_mac(mac).replace(':', '')
|
mac = format_mac(mac).replace(':', '')
|
||||||
|
|
236
lc_ldap.py
236
lc_ldap.py
|
@ -36,17 +36,29 @@
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
import os, sys, ldap, re, netaddr, datetime, copy, time, random
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import ldap
|
||||||
import ldap.filter
|
import ldap.filter
|
||||||
from ldap.modlist import addModlist, modifyModlist
|
from ldap.modlist import addModlist, modifyModlist
|
||||||
|
|
||||||
|
import re
|
||||||
|
import netaddr
|
||||||
|
import datetime
|
||||||
|
import copy
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Levenshtein import jaro
|
from Levenshtein import jaro
|
||||||
except ImportError:
|
except ImportError:
|
||||||
def jaro(a, b): return 0
|
def jaro(a, b): return 0
|
||||||
sys.path.append('/usr/scripts/gestion')
|
sys.path.append('/usr/scripts/gestion')
|
||||||
|
|
||||||
import config, crans_utils
|
import config
|
||||||
from attributs import attrify, blacklist
|
import crans_utils
|
||||||
|
from attributs import *
|
||||||
from ldap_locks import CransLock
|
from ldap_locks import CransLock
|
||||||
import ridtools
|
import ridtools
|
||||||
|
|
||||||
|
@ -54,6 +66,11 @@ uri = 'ldap://ldap.adm.crans.org/'
|
||||||
base_dn = 'ou=data,dc=crans,dc=org'
|
base_dn = 'ou=data,dc=crans,dc=org'
|
||||||
log_dn = "cn=log"
|
log_dn = "cn=log"
|
||||||
|
|
||||||
|
# Protection contre les typos
|
||||||
|
created = 'created'
|
||||||
|
modified = 'modified'
|
||||||
|
deleted = 'deleted'
|
||||||
|
|
||||||
# Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script
|
# Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script
|
||||||
# Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo)
|
# Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo)
|
||||||
# est plus pertinente que USER (qui sera root)
|
# est plus pertinente que USER (qui sera root)
|
||||||
|
@ -75,6 +92,10 @@ def escape(chaine):
|
||||||
return ldap.filter.escape_filter_chars(chaine)
|
return ldap.filter.escape_filter_chars(chaine)
|
||||||
|
|
||||||
def ldif_to_uldif(ldif):
|
def ldif_to_uldif(ldif):
|
||||||
|
"""
|
||||||
|
Transforme un dictionnaire ldif en un dictionnaire
|
||||||
|
ldif unicode.
|
||||||
|
"""
|
||||||
uldif = {}
|
uldif = {}
|
||||||
for attr, vals in ldif.items():
|
for attr, vals in ldif.items():
|
||||||
uldif[attr] = [ unicode(val, 'utf-8') for val in vals ]
|
uldif[attr] = [ unicode(val, 'utf-8') for val in vals ]
|
||||||
|
@ -92,6 +113,10 @@ def ldif_to_cldif(ldif, conn, check_ctxt = True):
|
||||||
return cldif
|
return cldif
|
||||||
|
|
||||||
def cldif_to_ldif(cldif):
|
def cldif_to_ldif(cldif):
|
||||||
|
"""
|
||||||
|
Transforme un ldif crans en ldif valide au sens openldap.
|
||||||
|
Ce ldif est celui qui sera transmis à la base.
|
||||||
|
"""
|
||||||
ldif = {}
|
ldif = {}
|
||||||
for attr, vals in cldif.items():
|
for attr, vals in cldif.items():
|
||||||
ldif[attr] = [ str(val) for val in vals ]
|
ldif[attr] = [ str(val) for val in vals ]
|
||||||
|
@ -108,6 +133,7 @@ def lc_ldap_admin():
|
||||||
secrets = import_secrets()
|
secrets = import_secrets()
|
||||||
return lc_ldap(uri='ldap://ldap.adm.crans.org/', dn=secrets.ldap_auth_dn, cred=secrets.ldap_password)
|
return lc_ldap(uri='ldap://ldap.adm.crans.org/', dn=secrets.ldap_auth_dn, cred=secrets.ldap_password)
|
||||||
|
|
||||||
|
|
||||||
class lc_ldap(ldap.ldapobject.LDAPObject):
|
class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
"""Connexion à la base ldap crans, chaque instance représente une connexion
|
"""Connexion à la base ldap crans, chaque instance représente une connexion
|
||||||
"""
|
"""
|
||||||
|
@ -147,7 +173,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
# Si on a un dn, on se connecte avec à la base ldap sinon on s'y
|
# Si on a un dn, on se connecte avec à la base ldap sinon on s'y
|
||||||
# connecte en anonyme
|
# connecte en anonyme
|
||||||
if dn:
|
if dn:
|
||||||
self.conn = self.bind_s(dn, cred)
|
self.conn = self.bind_s(secrets.ldap_auth_dn, secrets.ldap_password)
|
||||||
self.dn = dn
|
self.dn = dn
|
||||||
self.droits = self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])
|
self.droits = self.search_s(dn, ldap.SCOPE_BASE, attrlist=['droits'])[0][1].get('droits', [])
|
||||||
else:
|
else:
|
||||||
|
@ -155,13 +181,13 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
self.dn = None
|
self.dn = None
|
||||||
self.droits = []
|
self.droits = []
|
||||||
|
|
||||||
def search(self, filterstr='(objectClass=*)', mode='ro', dn= base_dn, scope= 2, sizelimit=400):
|
def search(self, filterstr='(objectClass=*)', mode='ro', dn= base_dn, scope=ldap.SCOPE_SUBTREE, sizelimit=1000):
|
||||||
"""La fonction de recherche dans la base ldap qui renvoie un liste de
|
"""La fonction de recherche dans la base ldap qui renvoie un liste de
|
||||||
CransLdapObjects. On utilise la feature de sizelimit de python ldap"""
|
CransLdapObjects. On utilise la feature de sizelimit de python ldap"""
|
||||||
ldap_res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit)
|
ldap_res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit)
|
||||||
ret = []
|
ret = []
|
||||||
for dn, ldif in ldap_res:
|
for dn, ldif in ldap_res:
|
||||||
ret.append(new_cransldapobject(self, dn, mode=mode))
|
ret.append(new_cransldapobject(self, dn, mode, ldif))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def allMachinesAdherents(self):
|
def allMachinesAdherents(self):
|
||||||
|
@ -213,20 +239,17 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
#adm, serveurs, bornes, wifi, adherents, gratuit ou personnel-ens"""
|
#adm, serveurs, bornes, wifi, adherents, gratuit ou personnel-ens"""
|
||||||
owner = self.search('objectClass=*', dn=parent, scope=0)[0]
|
owner = self.search('objectClass=*', dn=parent, scope=0)[0]
|
||||||
|
|
||||||
if realm in ["adm", "serveurs"]:
|
if realm in ["adm", "serveurs", "serveurs-v6", "adm-v6"]:
|
||||||
uldif['objectClass'] = [u'machineCrans']
|
uldif['objectClass'] = [u'machineCrans']
|
||||||
assert isinstance(owner, AssociationCrans)
|
assert isinstance(owner, AssociationCrans)
|
||||||
# XXX - Vérifier les droits
|
|
||||||
|
|
||||||
elif realm == "bornes":
|
elif realm == "bornes":
|
||||||
uldif['objectClass'] = [u'borneWifi']
|
uldif['objectClass'] = [u'borneWifi']
|
||||||
assert isinstance(owner, AssociationCrans)
|
assert isinstance(owner, AssociationCrans)
|
||||||
# XXX - Vérifier les droits
|
|
||||||
|
|
||||||
elif realm in ["wifi", "wifi-v6"]:
|
elif realm in ["wifi", "wifi-v6"]:
|
||||||
uldif['objectClass'] = [u'machineWifi']
|
uldif['objectClass'] = [u'machineWifi']
|
||||||
assert isinstance(owner, adherent) or isinstance(owner, club)
|
assert isinstance(owner, adherent) or isinstance(owner, club)
|
||||||
# XXX - Vérifier les droits (owner.type_connexion)
|
|
||||||
|
|
||||||
elif realm in ["fil", "fil-v6", "personnel-ens"]:
|
elif realm in ["fil", "fil-v6", "personnel-ens"]:
|
||||||
uldif['objectClass'] = [u'machineFixe']
|
uldif['objectClass'] = [u'machineFixe']
|
||||||
|
@ -234,26 +257,43 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
|
|
||||||
else: raise ValueError("Realm inconnu: %r" % realm)
|
else: raise ValueError("Realm inconnu: %r" % realm)
|
||||||
|
|
||||||
# On récupère la plage des mids
|
|
||||||
plage = xrange( *(config.mid[realm]))
|
|
||||||
# On récupère le premier id libre dans la plages s'il n'est pas
|
# On récupère le premier id libre dans la plages s'il n'est pas
|
||||||
# déjà précisé dans le ldiff
|
# déjà précisé dans le ldiff
|
||||||
mid = uldif.setdefault('mid', [ unicode(self._find_id('mid', plage)) ])
|
rid = uldif.setdefault('rid', [ unicode(self._find_id('rid', plage)) ])
|
||||||
|
|
||||||
|
# La machine peut-elle avoir une ipv4 ?
|
||||||
if 'v6' not in realm:
|
if 'v6' not in realm:
|
||||||
uldif['ipHostNumber'] = [ unicode(crans_utils.ip4_of_mid(int (mid[0]))) ]
|
uldif['ipHostNumber'] = [ unicode(crans_utils.ip4_of_rid(rid[0])) ]
|
||||||
return self._create_entity('mid=%s,%s' % (mid[0], parent), uldif)
|
uldif['ip6HostNumber'] = [ unicode(crans_utils.ip6_of_mac(uldif['macAddress'][0], rid[0])) ]
|
||||||
|
|
||||||
|
# On récupère la plage des mids
|
||||||
|
plage = xrange( *(config.rid[realm]))
|
||||||
|
# Tout doit disparaître !!
|
||||||
|
machine = self._create_entity('mid=%s,%s' % (mid[0], parent), uldif)
|
||||||
|
if machine.may_be(created, self.droits + self._is_parent(machine)):
|
||||||
|
machine.create()
|
||||||
|
else:
|
||||||
|
raise EnvironmentError("Vous n'avez pas le droit de créer cette machine.")
|
||||||
|
|
||||||
def newAdherent(self, uldif):
|
def newAdherent(self, uldif):
|
||||||
"""Crée un nouvel adhérent"""
|
"""Crée un nouvel adhérent"""
|
||||||
aid = uldif.setdefault('aid', [ unicode(self._find_id('aid')) ])
|
aid = uldif.setdefault('aid', [ unicode(self._find_id('aid')) ])
|
||||||
uldif['objectClass'] = [u'adherent']
|
uldif['objectClass'] = [u'adherent']
|
||||||
return self._create_entity('aid=%s,%s' % (aid[0], base_dn), uldif)
|
adherent = self._create_entity('aid=%s,%s' % (aid[0], base_dn), uldif)
|
||||||
|
if adherent.may_be(created, self):
|
||||||
|
adherent.create()
|
||||||
|
else:
|
||||||
|
raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.")
|
||||||
|
|
||||||
def newClub(self, uldif):
|
def newClub(self, uldif):
|
||||||
"""Crée un nouveau club"""
|
"""Crée un nouveau club"""
|
||||||
cid = uldif.setdefault('cid', [ unicode(self._find_id('cid')) ])
|
cid = uldif.setdefault('cid', [ unicode(self._find_id('cid')) ])
|
||||||
uldif['objectClass'] = [u'club']
|
uldif['objectClass'] = [u'club']
|
||||||
return self._create_entity('cid=%s,%s' % (cid[0], base_dn), uldif)
|
club = self._create_entity('cid=%s,%s' % (cid[0], base_dn), uldif)
|
||||||
|
if club.may_be(created, self):
|
||||||
|
club.create()
|
||||||
|
else:
|
||||||
|
raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.")
|
||||||
|
|
||||||
def newFacture(self, uldif):
|
def newFacture(self, uldif):
|
||||||
"""Crée une nouvelle facture
|
"""Crée une nouvelle facture
|
||||||
|
@ -267,31 +307,53 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
|
||||||
cldif = ldif_to_cldif(uldif, self)
|
cldif = ldif_to_cldif(uldif, self)
|
||||||
# Conversion en ascii
|
# Conversion en ascii
|
||||||
ldif = cldif_to_ldif(cldif)
|
ldif = cldif_to_ldif(cldif)
|
||||||
# Création de la requête LDAP
|
|
||||||
modlist = addModlist(ldif)
|
|
||||||
# Requête LDAP de création de l'objet
|
|
||||||
self.add_s(dn, modlist)
|
|
||||||
# Renvoi du CransLdapObject
|
# Renvoi du CransLdapObject
|
||||||
return new_cransldapobject(self, dn, mode='w')
|
return new_cransldapobject(self, dn, 'rw', ldif)
|
||||||
|
|
||||||
|
def _find_id(self, attr, plage=None):
|
||||||
def _find_id(self, attr, plage = xrange(1, 32000)):
|
'''Trouve un id libre. Si une plage est fournie, cherche
|
||||||
'''Trouve un <attr>id libre dans plage'''
|
l'id dans celle-ci, sinon, prend le plus élevé possible.'''
|
||||||
res = self.search_s(base_dn, 2, '%s=*' % attr, attrlist = [attr])
|
res = self.search_s(base_dn, ldap.SCOPE_SUBTREE, '%s=*' % attr, attrlist = [attr])
|
||||||
nonfree = [ int(r[1].get(attr)[0]) for r in res if r[1].get(attr) ]
|
nonfree = [ int(r[1].get(attr)[0]) for r in res if r[1].get(attr) ]
|
||||||
nonfree.sort()
|
nonfree.sort()
|
||||||
|
|
||||||
for i in plage:
|
if plage != None:
|
||||||
if nonfree and nonfree[0] <= i:
|
for i in plage:
|
||||||
while nonfree and nonfree[0] <= i:
|
if i in nonfree:
|
||||||
nonfree = nonfree[1:]
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
break
|
raise EnvironmentError('Aucun %s libre dans la plage [%d, %d]' %
|
||||||
|
(attr, plage[0], i))
|
||||||
else:
|
else:
|
||||||
raise EnvironmentError('Aucun %s libre dans la plage [%d, %d]' %
|
i = nonfree[-1]+1
|
||||||
(attr, plage[0], i))
|
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
def _is_parent(self, obj):
|
||||||
|
"""
|
||||||
|
Teste le lien de parenté de l'objet 1 sur l'objet 2.
|
||||||
|
Retourne une liste qui s'ajoutera à la liste des droits
|
||||||
|
"""
|
||||||
|
|
||||||
|
if obj.dn.endswith(self.dn) and obj.dn != self.dn:
|
||||||
|
return [parent]
|
||||||
|
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def _is_self(obj1, obj2):
|
||||||
|
"""
|
||||||
|
Teste si l'objet qui se binde est celui qui est en cours de modif.
|
||||||
|
Retourne une liste qui s'ajoutera à la liste des droits
|
||||||
|
"""
|
||||||
|
|
||||||
|
if obj.dn == self.dn:
|
||||||
|
return [soi]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def new_cransldapobject(conn, dn, mode='ro', ldif = None):
|
def new_cransldapobject(conn, dn, mode='ro', ldif = None):
|
||||||
"""Crée un objet CransLdap en utilisant la classe correspondant à
|
"""Crée un objet CransLdap en utilisant la classe correspondant à
|
||||||
|
@ -317,6 +379,11 @@ class CransLdapObject(object):
|
||||||
"""Classe de base des objets CransLdap.
|
"""Classe de base des objets CransLdap.
|
||||||
Cette classe ne devrait pas être utilisée directement."""
|
Cette classe ne devrait pas être utilisée directement."""
|
||||||
|
|
||||||
|
can_be_by = { created: [nounou],
|
||||||
|
modified: [nounou],
|
||||||
|
deleted: [nounou],
|
||||||
|
}
|
||||||
|
|
||||||
""" Champs uniques et nécessaires """
|
""" Champs uniques et nécessaires """
|
||||||
ufields = []
|
ufields = []
|
||||||
|
|
||||||
|
@ -348,36 +415,48 @@ class CransLdapObject(object):
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
self.dn = dn
|
self.dn = dn
|
||||||
|
|
||||||
|
orig = {}
|
||||||
if ldif:
|
if ldif:
|
||||||
# Vous précisez un ldif, l'objet est 'ro'
|
|
||||||
self.mode = 'ro'
|
|
||||||
self.attrs = ldif
|
self.attrs = ldif
|
||||||
if dn != base_dn: # new_cransldapobject ne donne pas de ldif formaté et utilise un ldif non formaté, donc on formate
|
if dn != base_dn: # new_cransldapobject ne donne pas de ldif formaté et utilise un ldif non formaté, donc on formate
|
||||||
self.attrs = ldif_to_uldif(self.attrs)
|
self.attrs = ldif_to_uldif(self.attrs)
|
||||||
self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False) # on est en read only, donc pas la peine de vérifier la validité
|
self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = True)
|
||||||
|
self._modifs = ldif_to_uldif(ldif)
|
||||||
|
self._modifs = ldif_to_cldif(self._modifs, conn, check_ctxt = False)
|
||||||
|
orig = ldif
|
||||||
|
|
||||||
elif dn != base_dn:
|
elif dn != base_dn:
|
||||||
res = conn.search_s(dn, 0)
|
res = conn.search_s(dn, 0)
|
||||||
if not res:
|
if not res:
|
||||||
raise ValueError ('objet inexistant: %s' % dn)
|
raise ValueError ('objet inexistant: %s' % dn)
|
||||||
self.dn, self.attrs = res[0]
|
self.dn, self.attrs = res[0]
|
||||||
|
|
||||||
|
# Pour test en cas de mode w ou rw
|
||||||
|
orig = res[0][1]
|
||||||
|
|
||||||
self.attrs = ldif_to_uldif(self.attrs)
|
self.attrs = ldif_to_uldif(self.attrs)
|
||||||
|
# L'objet sortant de la base ldap, on ne fait pas de vérifications sur
|
||||||
|
# l'état des données.
|
||||||
self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False)
|
self.attrs = ldif_to_cldif(self.attrs, conn, check_ctxt = False)
|
||||||
if mode in ['w', 'rw']:
|
self._modifs = ldif_to_cldif(ldif_to_uldif(res[0][1]), conn, check_ctxt = False)
|
||||||
### Vérification que `λv. str(Attr(v))` est bien une projection
|
|
||||||
### C'est-à-dire que si on str(Attr(str(Attr(v)))) on retombe sur str(Attr(v))
|
|
||||||
oldif = res[0][1]
|
|
||||||
nldif = cldif_to_ldif(self.attrs)
|
|
||||||
|
|
||||||
for attr, vals in oldif.items():
|
# Je m'interroge sur la pertinence de cette partie, je pense qu'elle n'est
|
||||||
if nldif[attr] != vals:
|
# pas utile. -- PEB 27/01/2013
|
||||||
for v in nldif[attr]:
|
if mode in ['w', 'rw']:
|
||||||
if v in vals:
|
### Vérification que `λv. str(Attr(v))` est bien une projection
|
||||||
vals.remove(v)
|
### C'est-à-dire que si on str(Attr(str(Attr(v)))) on retombe sur str(Attr(v))
|
||||||
nvals = [nldif[attr][v.index(v)] for v in vals ]
|
oldif = orig
|
||||||
raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals)
|
nldif = cldif_to_ldif(self.attrs)
|
||||||
|
|
||||||
self._modifs = ldif_to_cldif(ldif_to_uldif(res[0][1]), conn, check_ctxt = False)
|
for attr, vals in oldif.items():
|
||||||
|
if nldif[attr] != vals:
|
||||||
|
for v in nldif[attr]:
|
||||||
|
if v in vals:
|
||||||
|
vals.remove(v)
|
||||||
|
nvals = [nldif[attr][v.index(v)] for v in vals ]
|
||||||
|
raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _get_fields(self):
|
def _get_fields(self):
|
||||||
"""Renvoie la liste des champs LDAP de l'objet"""
|
"""Renvoie la liste des champs LDAP de l'objet"""
|
||||||
|
@ -387,7 +466,7 @@ class CransLdapObject(object):
|
||||||
def history_add(self, login, chain):
|
def history_add(self, login, chain):
|
||||||
"""Ajoute une ligne à l'historique de l'objet.
|
"""Ajoute une ligne à l'historique de l'objet.
|
||||||
###ATTENTION : C'est un kludge pour pouvoir continuer à faire "comme avant",
|
###ATTENTION : C'est un kludge pour pouvoir continuer à faire "comme avant",
|
||||||
### mais on devrait tout recoder pour utiliser l'historique LDAP"""
|
### mais on devrait tout recoder pour utiliser l'historique LDAP"""
|
||||||
assert isinstance(login, str) or isinstance(login, unicode)
|
assert isinstance(login, str) or isinstance(login, unicode)
|
||||||
assert isinstance(chain, unicode)
|
assert isinstance(chain, unicode)
|
||||||
|
|
||||||
|
@ -395,6 +474,16 @@ class CransLdapObject(object):
|
||||||
# Attention, le __setitem__ est surchargé, mais pas .append sur l'historique
|
# Attention, le __setitem__ est surchargé, mais pas .append sur l'historique
|
||||||
self["historique"] = self["historique"] + [new_line]
|
self["historique"] = self["historique"] + [new_line]
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
"""Crée l'objet dans la base ldap, cette méthode vise à faire en sorte que
|
||||||
|
l'objet se crée lui-même, si celui qui essaye de le modifier a les droits
|
||||||
|
de le faire."""
|
||||||
|
|
||||||
|
# Création de la requête LDAP
|
||||||
|
modlist = addModlist(cldif_to_ldif(self.attrs))
|
||||||
|
# Requête LDAP de création de l'objet
|
||||||
|
self.add_s(self.dn, modlist)
|
||||||
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Sauvegarde dans la base les modifications apportées à l'objet.
|
"""Sauvegarde dans la base les modifications apportées à l'objet.
|
||||||
|
@ -405,7 +494,10 @@ class CransLdapObject(object):
|
||||||
|
|
||||||
# On récupère la liste des modifications
|
# On récupère la liste des modifications
|
||||||
modlist = self.get_modlist()
|
modlist = self.get_modlist()
|
||||||
self.conn.modify_s(self.dn, modlist)
|
try:
|
||||||
|
self.conn.modify_s(self.dn, modlist)
|
||||||
|
except:
|
||||||
|
raise EnvironmentError("Impossible de modifier l'objet, peut-être n'existe-t-il pas ?")
|
||||||
|
|
||||||
# Vérification des modifications
|
# Vérification des modifications
|
||||||
self.attrs = ldif_to_uldif(self.conn.search_s(self.dn, 0)[0][1])
|
self.attrs = ldif_to_uldif(self.conn.search_s(self.dn, 0)[0][1])
|
||||||
|
@ -420,6 +512,16 @@ class CransLdapObject(object):
|
||||||
if differences:
|
if differences:
|
||||||
raise EnvironmentError("Les modifications apportées à l'objet %s n'ont pas été correctement sauvegardées\n%s" % (self.dn, differences))
|
raise EnvironmentError("Les modifications apportées à l'objet %s n'ont pas été correctement sauvegardées\n%s" % (self.dn, differences))
|
||||||
|
|
||||||
|
def may_be(self, what, obj):
|
||||||
|
"""Teste si celui qui est bindé peut effectuer ce qui est dans what, pour
|
||||||
|
what élément de {create, delete, modify}.
|
||||||
|
Retourne un booléen
|
||||||
|
"""
|
||||||
|
if set(obj.droits).intersection(self.can_be_by[what]) != set([]):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def get_modlist(self):
|
def get_modlist(self):
|
||||||
"""Renvoie un dictionnaire des modifications apportées à l'objet"""
|
"""Renvoie un dictionnaire des modifications apportées à l'objet"""
|
||||||
# unicode -> utf-8
|
# unicode -> utf-8
|
||||||
|
@ -475,9 +577,9 @@ class CransLdapObject(object):
|
||||||
if res != []:
|
if res != []:
|
||||||
author = res[0].compte()
|
author = res[0].compte()
|
||||||
|
|
||||||
if attrs['reqType'][0] == 'delete':
|
if attrs['reqType'][0] == deleted:
|
||||||
out.append(u"%s : [%s] Suppression" % (date, author))
|
out.append(u"%s : [%s] Suppression" % (date, author))
|
||||||
elif attrs['reqType'][0] == 'modify':
|
elif attrs['reqType'][0] == modified:
|
||||||
fields = {}
|
fields = {}
|
||||||
for mod in attrs['reqMod']:
|
for mod in attrs['reqMod']:
|
||||||
mod = mod.decode('utf-8')
|
mod = mod.decode('utf-8')
|
||||||
|
@ -534,6 +636,11 @@ class CransLdapObject(object):
|
||||||
|
|
||||||
class proprio(CransLdapObject):
|
class proprio(CransLdapObject):
|
||||||
u""" Un propriétaire de machine (adhérent, club…) """
|
u""" Un propriétaire de machine (adhérent, club…) """
|
||||||
|
can_be_by = { created: [nounou, bureau, cableur],
|
||||||
|
modified: [nounou, bureau, soi, cableur],
|
||||||
|
deleted: [nounou, bureau],
|
||||||
|
}
|
||||||
|
|
||||||
ufields = [ 'nom', 'chbre' ]
|
ufields = [ 'nom', 'chbre' ]
|
||||||
mfields = [ 'paiement', 'info', 'blacklist', 'controle']
|
mfields = [ 'paiement', 'info', 'blacklist', 'controle']
|
||||||
ofields = []
|
ofields = []
|
||||||
|
@ -623,11 +730,16 @@ class proprio(CransLdapObject):
|
||||||
|
|
||||||
class machine(CransLdapObject):
|
class machine(CransLdapObject):
|
||||||
u""" Une machine """
|
u""" Une machine """
|
||||||
|
can_be_by = { created: [nounou, bureau, cableur, parent],
|
||||||
|
modified: [nounou, bureau, cableur, parent],
|
||||||
|
deleted: [nounou, bureau, cableur, parent],
|
||||||
|
}
|
||||||
|
|
||||||
ufields = ['mid', 'macAddress', 'host', 'midType']
|
ufields = ['mid', 'macAddress', 'host', 'midType']
|
||||||
ofields = []
|
ofields = ['rid']
|
||||||
mfields = ['info', 'blacklist', 'hostAlias', 'exempt',
|
mfields = ['info', 'blacklist', 'hostAlias', 'exempt',
|
||||||
'portTCPout', 'portTCPin', 'portUDPout', 'portUDPin','sshFingerprint']
|
'portTCPout', 'portTCPin', 'portUDPout', 'portUDPin','sshFingerprint', 'ipHostNumber', 'ip6HostNumber']
|
||||||
xfields = ['ipHostNumber']
|
xfields = []
|
||||||
|
|
||||||
def __init__(self, conn, dn, mode='ro', ldif = None):
|
def __init__(self, conn, dn, mode='ro', ldif = None):
|
||||||
super(machine, self).__init__(conn, dn, mode, ldif)
|
super(machine, self).__init__(conn, dn, mode, ldif)
|
||||||
|
@ -746,14 +858,26 @@ class machineWifi(machine):
|
||||||
ufields = machine.ufields + ['ipsec']
|
ufields = machine.ufields + ['ipsec']
|
||||||
|
|
||||||
class machineCrans(machine):
|
class machineCrans(machine):
|
||||||
|
can_be_by = { created: [nounou],
|
||||||
|
modified: [nounou],
|
||||||
|
deleted: [nounou],
|
||||||
|
}
|
||||||
ufields = machine.ufields + ['prise']
|
ufields = machine.ufields + ['prise']
|
||||||
ofields = machine.ofields + ['nombrePrises']
|
ofields = machine.ofields + ['nombrePrises']
|
||||||
|
|
||||||
class borneWifi(machine):
|
class borneWifi(machine):
|
||||||
|
can_be_by = { created: [nounou],
|
||||||
|
modified: [nounou],
|
||||||
|
deleted: [nounou],
|
||||||
|
}
|
||||||
ufields = machine.ufields + ['canal', 'puissance', 'hotspot',
|
ufields = machine.ufields + ['canal', 'puissance', 'hotspot',
|
||||||
'prise', 'positionBorne', 'nvram']
|
'prise', 'positionBorne', 'nvram']
|
||||||
|
|
||||||
class facture(CransLdapObject):
|
class facture(CransLdapObject):
|
||||||
|
can_be_by = { created: [nounou, bureau, cableur],
|
||||||
|
modified: [nounou, bureau, cableur],
|
||||||
|
deleted: [nounou, bureau, cableur],
|
||||||
|
}
|
||||||
ufields = ['fid', 'modePaiement', 'recuPaiement']
|
ufields = ['fid', 'modePaiement', 'recuPaiement']
|
||||||
|
|
||||||
class service(CransLdapObject): pass
|
class service(CransLdapObject): pass
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue