Merge branch 'master' of sila:/git/ldap

This commit is contained in:
Valentin Samir 2011-10-28 20:32:15 +02:00
commit 6d4aad6b00
2 changed files with 87 additions and 41 deletions

View file

@ -69,6 +69,7 @@ class Attr(object):
ldif: objet contenant l'attribut (permet de faire les validations sur l'environnement) ldif: objet contenant l'attribut (permet de faire les validations sur l'environnement)
ctxt_check: effectue les validations ctxt_check: effectue les validations
""" """
self.ctxt_check=ctxt_check
self.value = None self.value = None
self.conn = conn self.conn = conn
assert isinstance(val, unicode) assert isinstance(val, unicode)
@ -134,11 +135,13 @@ class objectClass(Attr):
optional = False optional = False
legend = "entité" legend = "entité"
def parse_value(self, val, ldif): def parse_value(self, val, ldif):
if val not in [ 'top', 'posixAccount', 'shadowAccount', 'proprio', if val not in [ 'top', 'posixAccount', 'shadowAccount', 'proprio',
'adherent', 'club', 'machine', 'machineCrans', 'adherent', 'club', 'machine', 'machineCrans',
'borneWifi', 'machineWifi', 'machineFixe', 'borneWifi', 'machineWifi', 'machineFixe',
'cransAccount', 'service', 'facture', 'freeMid' ]: 'cransAccount', 'service', 'facture', 'freeMid' ]:
print(val)
raise ValueError("Pourquoi insérer un objectClass=%s ?" % val) raise ValueError("Pourquoi insérer un objectClass=%s ?" % val)
else: else:
self.value = unicode(val) self.value = unicode(val)
@ -254,6 +257,7 @@ class chbre(Attr):
can_modify = ["self", "Cableur", "Nounou"] can_modify = ["self", "Cableur", "Nounou"]
def parse_value(self, val, ldif): def parse_value(self, val, ldif):
if self.ctxt_check: # Si ce n'est pas la peine de vérifier, on ne vérifie pas
if u'club' in ldif['objectClass']: if u'club' in ldif['objectClass']:
if val in annuaires_pg.locaux_clubs(): if val in annuaires_pg.locaux_clubs():
self.value = val self.value = val
@ -295,8 +299,8 @@ class solde(Attr):
can_modify = ["imprimeur", "Nounou", "Tresorier"] can_modify = ["imprimeur", "Nounou", "Tresorier"]
def parse_value(self, solde, ldif): def parse_value(self, solde, ldif):
# on évite les dépassements # on évite les dépassements, sauf si on nous dit de ne pas vérifier
if not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.): if self.ctxt_check and not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.):
raise ValueError("Solde invalide: %s" % solde) raise ValueError("Solde invalide: %s" % solde)
self.value = solde self.value = solde
@ -304,7 +308,7 @@ class dnsAttr(Attr):
def parse_value(self, dns, ldif): def parse_value(self, dns, ldif):
dns = dns.lower() dns = dns.lower()
name, net = dns.split('.', 1) name, net = dns.split('.', 1)
if (net not in ['crans.org', 'wifi.crans.org'] or if self.ctxt_check and (net not in ['crans.org', 'wifi.crans.org'] or
not re.match('[a-z][-_a-z0-9]+', name)): not re.match('[a-z][-_a-z0-9]+', name)):
raise ValueError("Nom d'hote invalide '%s'" % dns) raise ValueError("Nom d'hote invalide '%s'" % dns)
self.value = dns self.value = dns
@ -544,8 +548,12 @@ class loginShell(Attr):
'/usr/bin/rssh', '/usr/bin/rssh',
'/usr/local/bin/disconnect_shell', '/usr/local/bin/disconnect_shell',
'/usr/scripts/surveillance/disconnect_shell', '/usr/scripts/surveillance/disconnect_shell',
'/usr/local/bin/badPassSh',
'/usr/bin/passwd',
'/bin/false',
'/bin//zsh'
''] '']
if (shell not in shells): if self.ctxt_check and (shell not in shells):
raise ValueError("Shell %s invalide" % shell) raise ValueError("Shell %s invalide" % shell)
self.value = shell self.value = shell

View file

@ -121,32 +121,53 @@ class lc_ldap(ldap.ldapobject.LDAPObject):
res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit) res = self.search_ext_s(dn, scope, filterstr, sizelimit=sizelimit)
return [ new_cransldapobject(self, r[0], mode=mode) for r in res ] return [ new_cransldapobject(self, r[0], mode=mode) for r in res ]
def allMachinesAdherents(self):
"""Renvoie la liste de toutes les machines et de tous les adherents
(club et Association Crans compris). Conçue pour s'éxécuter le plus
rapidement possible. On dumpe malgré tout toute la base."""
res = {}
parent = {}
machines = {}
# (proxying de la base ldap)
for dn, attrs in self.search_s(base_dn, scope=2):
# On crée les listes des machines et propriétaires
if dn.startswith('mid='): # les machines
m = new_cransldapobject(self, dn, ldif = attrs)
parent_dn = dn.split(',', 1)[1]
if not machines.has_key(parent_dn):
machines[parent_dn]=[]
machines[parent_dn].append(m)
elif (dn.startswith('aid=') or dn.startswith('cid=') or dn==base_dn) and not parent.has_key(dn):
# Hélas on refait une recherche ldap dans attributs.py pour trouver les responsables des club
# ce qui prends un temps non négligeable mais est toujours mieux que de le faire pour tous les adherents
parent[dn]=new_cransldapobject(self, dn, ldif = attrs)
allmachines=[]
for dn,mlist in machines.items(): # on associe propriétaires et machines
parent[dn]._machines=mlist
for m in mlist:
m._proprio=parent[dn]
allmachines.append(m)
return allmachines,parent.values() # on renvoie la liste des machines et des adherents (dont club et crans)
def allMachines(self): def allMachines(self):
"""Renvoie la liste de toutes les machines, Conçue pour """Renvoie la liste de toutes les machines, Conçue pour
s'éxécuter le plus rapidement possible. On dumpe malgré tout s'éxécuter le plus rapidement possible. On dumpe malgré tout
toute la base, c'est pour pouvoir aussi rajouter à moindre coût toute la base, c'est pour pouvoir aussi rajouter à moindre coût
les propriétaires.""" les propriétaires."""
res = {} machines,_=self.allMachinesAdherents()
parent = {}
machines = []
# On récupère tous les objets ldap et on les met dans un dico
# (proxying de la base ldap)
for dn, attrs in self.search_s(base_dn, scope=2): #on fait tout dans une seule boucle
#~ res[dn] = attrs
# On crée la liste des machines
#~ for dn, attrs in res.items():
if dn.startswith('mid='):
m = new_cransldapobject(self, dn, ldif = attrs)
parent_dn = dn.split(',', 1)[1]
if not parent.has_key(parent_dn):
parent[parent_dn]=adherent(self, dn,machines= [ new_cransldapobject(self, dn,ldif=attrs)]) # on utilise pas new_cransldapobject pour optimiser les appel ldap (on passe la liste des machines)
else:
parent[parent_dn]._machines.append(new_cransldapobject(self, dn,ldif=attrs))
#~ m._proprio = new_cransldapobject(self, parent_dn, res[parent_dn],opt=machine_proprio[parent_dn])
m._proprio = parent[parent_dn]
machines.append(m)
return machines return machines
def allAdherents(self):
"""Renvoie la liste de toutes les adherents, Conçue pour
s'éxécuter le plus rapidement possible. On dumpe malgré tout
toute la base, c'est pour pouvoir aussi rajouter à moindre coût
les machines."""
_,adherents=self.allMachinesAdherents()
return adherents
def newMachine(self, parent, realm, uldif): def newMachine(self, parent, realm, uldif):
"""Crée une nouvelle machine: realm peut être: """Crée une nouvelle machine: realm peut être:
fil, fil-v6, wifi, wifi-v6, adm, gratuit, personnel-ens, special""" fil, fil-v6, wifi, wifi-v6, adm, gratuit, personnel-ens, special"""
@ -241,10 +262,10 @@ def new_cransldapobject(conn, dn, mode='ro', ldif = None):
classe = None classe = None
if ldif: if dn == base_dn:
classe = globals()[ldif['objectClass'][0]]
elif dn == base_dn:
classe = AssociationCrans classe = AssociationCrans
elif ldif:
classe = globals()[ldif['objectClass'][0]]
else: else:
res = conn.search_s(dn, 0) res = conn.search_s(dn, 0)
if not res: if not res:
@ -265,7 +286,7 @@ class CransLdapObject(object):
self.mode = mode self.mode = mode
self.attrs = None # Contient un dico uldif qui doit représenter ce qui self.attrs = {} # Contient un dico uldif qui doit représenter ce qui
# est dans la base # est dans la base
self._modifs = None # C'est là qu'on met les modifications self._modifs = None # C'est là qu'on met les modifications
@ -279,6 +300,9 @@ class CransLdapObject(object):
# Vous précisez un ldif, l'objet est 'ro' # Vous précisez un ldif, l'objet est 'ro'
self.mode = '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
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é
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:
@ -395,7 +419,7 @@ class CransLdapObject(object):
# XXX - Proposer de filtrer les blacklistes avec un arg supplémentaire ? # XXX - Proposer de filtrer les blacklistes avec un arg supplémentaire ?
# XXX - Vérifier les blacklistes des machines pour les adhérents ? # XXX - Vérifier les blacklistes des machines pour les adhérents ?
attrs = (self.attrs if self.mode not in ["w", "rw"] else self._modifs) attrs = (self.attrs if self.mode not in ["w", "rw"] else self._modifs)
return filter((lambda bl: bl.is_actif()), attrs.get("blacklist")) return filter((lambda bl: bl.is_actif()), attrs.get("blacklist",[]))
def blacklist(self, sanction, commentaire, debut="now", fin = '-'): def blacklist(self, sanction, commentaire, debut="now", fin = '-'):
u""" u"""
@ -425,6 +449,20 @@ class proprio(CransLdapObject):
super(proprio, self).__init__(conn, dn, mode, ldif) super(proprio, self).__init__(conn, dn, mode, ldif)
self._machines = machines self._machines = machines
def paiement_ok(self):
"""Renvoie si le propriétaire à payé pour l'année en cours"""
if self.dn == base_dn:
return True
try:
for paiement in self['paiement']:
if paiement.value == config.ann_scol:
return True
except KeyError:
pass
return False
def machines(self): def machines(self):
if not self._machines: if not self._machines:
self._machines = self.conn.search('mid=*', dn = self.dn, scope = 1) self._machines = self.conn.search('mid=*', dn = self.dn, scope = 1)