Compare commits

..

No commits in common. "master" and "peb_dev" have entirely different histories.

12 changed files with 301 additions and 660 deletions

View file

@ -47,8 +47,7 @@ import random
import string import string
from unicodedata import normalize from unicodedata import normalize
from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac, fetch_cert_info from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac, fetch_cert_info
from crans_utils import to_generalized_time_format, from_generalized_time_format, datetime_from_generalized_time_format from crans_utils import to_generalized_time_format, from_generalized_time_format
from crans_utils import datetime_to_generalized_time_format
import itertools import itertools
if '/usr/scripts' not in sys.path: if '/usr/scripts' not in sys.path:
@ -243,7 +242,7 @@ class AttrsDict(dict):
""" """
ldif = {} ldif = {}
for attr, vals in self.items(): for attr, vals in self.items():
ldif[attr] = [unicode(val).encode(config.ldap_encoding) for val in vals] ldif[attr] = [ str(val) for val in vals ]
return ldif return ldif
class Attr(object): class Attr(object):
@ -351,7 +350,9 @@ class Attr(object):
raise UniquenessError("%s déjà existant" % attr, [r.dn for r in res]) raise UniquenessError("%s déjà existant" % attr, [r.dn for r in res])
def is_modifiable(self, liste_droits): def is_modifiable(self, liste_droits):
"""L'attribut est-il modifiable par un des droits dans liste_droits ?""" """
L'attribut est-il modifiable par un des droits dans liste_droits ?
"""
return not set(liste_droits).isdisjoint(self.can_modify) return not set(liste_droits).isdisjoint(self.can_modify)
class AttributeFactory(object): class AttributeFactory(object):
@ -392,26 +393,13 @@ class rightProtectedAttr(Attr):
""" """
On permet la modification à un utilisateur On permet la modification à un utilisateur
""" """
# Si on est soi-même, on peut changer son mot de passe sans condition
if not soi in liste_droits: if not soi in liste_droits:
modifiables = set() modifiables = set()
# On regarde la liste des droits qu'a la connexion courante, ce sont a priori
# les droits de l'utilisateur qui modifie le mot de passe, ajoutés de soi/parent
# les cas échéants.
for i in liste_droits: for i in liste_droits:
# Si le droit est un droit "superviseur" (ie ayant le droit de modifier certains
# utilisateurs ayant un des droits "supervisés", on ajoute la liste des droits
# supervisés aux droits modifiables
if i in DROITS_SUPERVISEUR: if i in DROITS_SUPERVISEUR:
modifiables = modifiables.union(DROITS_SUPERVISEUR[i]) modifiables = modifiables.union(DROITS_SUPERVISEUR[i])
modifiables = list(modifiables) modifiables = list(modifiables)
# On prend les droits de l'utilisateur dont on cherche à modifier le mot de passe
# et on les compare à la liste des droits que l'utilisateur qui modifie a le droit
# de modifier. S'il y en a un qui n'est pas dans la liste des droits modifiables, on jette.
for droit in self.parent.get('droits', []): for droit in self.parent.get('droits', []):
if droit not in modifiables and droit in TOUS_DROITS: if droit not in modifiables and droit in TOUS_DROITS:
return False return False
@ -525,14 +513,14 @@ class aid(intAttr):
self.value = int(aid) self.value = int(aid)
@crans_attribute @crans_attribute
class uid(rightProtectedAttr): class uid(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
option = False option = False
legend = u"L'identifiant canonique de l'adhérent" legend = u"L'identifiant canonique de l'adhérent"
category = 'perso' category = 'perso'
unique = True unique = True
can_modify = [cableur, nounou] can_modify = [nounou]
ldap_name = "uid" ldap_name = "uid"
@crans_attribute @crans_attribute
@ -648,31 +636,25 @@ class generalizedTimeFormat(Attr):
une donnée de temps suivant la RFC 4517 une donnée de temps suivant la RFC 4517
""" """
__slots__ = ("datetime",) __slots__ = ("_stamp",)
python_type = datetime.datetime default = "19700101000000Z"
default = datetime_from_generalized_time_format("19700101000000Z")
def __unicode__(self):
return unicode(datetime_to_generalized_time_format(self.value))
def __float__(self): def __float__(self):
return from_generalized_time_format(unicode(self)) return self._stamp
def __int__(self): def __int__(self):
return int(float(self)) return int(self._stamp)
def __eq__(self, othertime): def __eq__(self, othertime):
if isinstance(othertime, generalizedTimeFormat): if isinstance(othertime, generalizedTimeFormat):
return self.value == othertime.value return self._stamp == othertime._stamp
elif isinstance(othertime, float): elif isinstance(othertime, float):
return float(self) == othertime return self._stamp == othertime
elif isinstance(othertime, int): elif isinstance(othertime, int):
return int(self) == othertime return self._stamp == othertime
elif isinstance(othertime, unicode) or isinstance(othertime, str): elif isinstance(othertime, unicode) or isinstance(othertime, str):
resource = generalizedTimeFormat(othertime, conn=None, Parent=None) resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
return self == resource return self._stamp == resource._stamp
elif isinstance(othertime, datetime.datetime):
return self.value == othertime
else: else:
return False return False
@ -681,16 +663,14 @@ class generalizedTimeFormat(Attr):
def __lt__(self, othertime): def __lt__(self, othertime):
if isinstance(othertime, generalizedTimeFormat): if isinstance(othertime, generalizedTimeFormat):
return self.value < othertime.value return self._stamp < othertime._stamp
elif isinstance(othertime, float): elif isinstance(othertime, float):
return float(self) < othertime return self._stamp < othertime
elif isinstance(othertime, int): elif isinstance(othertime, int):
return int(self) < othertime return self._stamp < othertime
elif isinstance(othertime, unicode) or isinstance(othertime, str): elif isinstance(othertime, unicode) or isinstance(othertime, str):
resource = generalizedTimeFormat(othertime, conn=None, Parent=None) resource = generalizedTimeFormat(othertime, conn=None, Parent=None)
return self < resource return self._stamp < resource._stamp
elif isinstance(othertime, datetime.datetime):
return self.value < othertime
else: else:
return False return False
@ -705,9 +685,15 @@ class generalizedTimeFormat(Attr):
def parse_value(self, gtf): def parse_value(self, gtf):
if isinstance(gtf, str) or isinstance(gtf, unicode): if isinstance(gtf, str) or isinstance(gtf, unicode):
self.value = datetime_from_generalized_time_format(gtf) if not ('Z' in gtf or '+' in gtf or '-' in gtf):
elif isinstance(gtf, datetime.datetime): self._stamp = gtf
self.value = gtf self.value = to_generalized_time_format(float(gtf))
else:
self._stamp = from_generalized_time_format(gtf)
self.value = gtf
elif isinstance(gtf, float):
self._stamp = gtf
self.value = to_generalized_time_format(gtf)
@crans_attribute @crans_attribute
class debutAdhesion(generalizedTimeFormat): class debutAdhesion(generalizedTimeFormat):
@ -754,43 +740,28 @@ class mail(rightProtectedAttr):
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
attr = self.__class__.__name__ attr = self.__class__.__name__
if str(self) in liste_exclue: if str(self) in liste_exclue:
return return
if attr in ["mailAlias", "canonicalAlias", 'mail']:
mail, end = str(self).split('@', 1)
if end.startswith('crans'):
try:
smtp = smtplib.SMTP(smtpserv)
smtp.putcmd("vrfy", mail)
res = smtp.getreply()[0] in [250, 252]
smtp.close()
except:
raise ValueError('Serveur de mail injoignable')
# On initialise le résultat, s'il vaut true en fin de course, le mail if res:
# est déjà pris. raise ValueError("Le mail %s est déjà pris." % (str(self)))
res = False else:
check = self.conn.search(u'mail=%s' % mail)
mail = str(self) if len(check) >= 1:
raise ValueError("Le mail %s est déjà pris." % (str(self)))
_, domain = mail.split('@')
if domain in config.dns.mail_crans:
# On commence par vérifier auprès du serveur SMTP
# si l'adresse email est prise sur le réseau. Cela permet
# de tester aussi les adresses statiquement écrites dans
# aliases.db.
try:
smtp = smtplib.SMTP(smtpserv)
smtp.putcmd("vrfy", mail)
res = smtp.getreply()[0] in [250, 252]
smtp.close()
except:
print 'Serveur de mail injoignable'
check = self.conn.search(
u'(|(mail=%(mail)s)(mailAlias=%(mail)s)(canonicalAlias=%(mail)s)(mailExt=%(mail)s))' % {
'mail': mail,
}
)
if len(check) >= 1:
res = True
if res:
raise ValueError("Le mail %s est déjà pris." % (str(self)))
def parse_value(self, mail): def parse_value(self, mail):
if not re.match(u'^[-+_.0-9A-Za-z]+@([A-Za-z0-9]{1}[A-Za-z0-9-_]+[.])+[a-z]{2,20}$', mail): if not re.match(u'^[-_.0-9A-Za-z]+@([A-Za-z0-9]{1}[A-Za-z0-9-_]+[.])+[a-z]{2,6}$', mail):
raise ValueError("%s invalide %r" % (self.legend, mail)) raise ValueError("%s invalide %r" % (self.legend, mail))
self.value = mail self.value = mail
@ -816,6 +787,7 @@ class mailAlias(mail):
optional = True optional = True
unique = True unique = True
legend = u"Alias mail" legend = u"Alias mail"
can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailAlias" ldap_name = "mailAlias"
@ -835,7 +807,8 @@ class mailExt(mail):
singlevalue = False singlevalue = False
optional = True optional = True
unique = True unique = True
legend = u"Mail de redirection ou de secours" legend = u"Mail de secours"
can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailExt" ldap_name = "mailExt"
@ -890,7 +863,7 @@ class chbre(Attr):
def parse_value(self, chambre): def parse_value(self, chambre):
if self.parent != None and u'club' in [str(o) for o in self.parent['objectClass']]: if self.parent != None and u'club' in [str(o) for o in self.parent['objectClass']]:
if chambre in annuaires_pg.locaux_clubs() or chambre in (u"EXT", u"????"): if chambre in annuaires_pg.locaux_clubs():
self.value = chambre self.value = chambre
else: else:
raise ValueError("Club devrait etre en XclN, pas en %r" % chambre) raise ValueError("Club devrait etre en XclN, pas en %r" % chambre)
@ -1082,6 +1055,7 @@ class rid(intAttr):
unique = True unique = True
legend = u"Identifiant réseau de machine" legend = u"Identifiant réseau de machine"
category = 'id' category = 'id'
can_modify = [nounou]
ldap_name = "rid" ldap_name = "rid"
def parse_value(self, rid): def parse_value(self, rid):
@ -1113,7 +1087,7 @@ class ipsec(Attr):
legend = u'Clef wifi' legend = u'Clef wifi'
category = 'wifi' category = 'wifi'
ldap_name = "ipsec" ldap_name = "ipsec"
can_modify = [nounou, cableur, parent] can_modify = [nounou, parent]
historique = "info" historique = "info"
default = u'auto' default = u'auto'
@ -1132,8 +1106,8 @@ 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]
ldap_name = "puissance" ldap_name = "puissance"
default = '60'
@crans_attribute @crans_attribute
class canal(intAttr): class canal(intAttr):
@ -1142,8 +1116,8 @@ class canal(intAttr):
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]
ldap_name = "canal" ldap_name = "canal"
default = "11"
@crans_attribute @crans_attribute
class hotspot(boolAttr): class hotspot(boolAttr):
@ -1152,24 +1126,25 @@ class hotspot(boolAttr):
optional = True optional = True
legend = u'Hotspot' legend = u'Hotspot'
category = 'wifi' category = 'wifi'
can_modify = [nounou]
ldap_name = "hotspot" ldap_name = "hotspot"
default = "FALSE"
@crans_attribute @crans_attribute
class positionBorne(Attr): class positionBorne(Attr):
__slots__ = () __slots__ = ()
legend = u"Position de la borne" legend = u"Position de la borne"
category = "wifi" category = "wifi"
can_modify = [nounou]
singlevalue = True singlevalue = True
optional = True optional = True
ldap_name = "positionBorne" ldap_name = "positionBorne"
default = "0 0"
@crans_attribute @crans_attribute
class nvram(Attr): class nvram(Attr):
__slots__ = () __slots__ = ()
legend = u"Configuration speciale" legend = u"Configuration speciale"
optional = True optional = True
can_modify = [nounou]
ldap_name = "nvram" ldap_name = "nvram"
class portAttr(Attr): class portAttr(Attr):
@ -1178,6 +1153,7 @@ class portAttr(Attr):
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): def parse_value(self, port):
if ":" in port: if ":" in port:
@ -1251,6 +1227,7 @@ class nombrePrises(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
categoriy = 'base_tech' categoriy = 'base_tech'
can_modify = [nounou]
ldap_name = "nombrePrises" ldap_name = "nombrePrises"
@crans_attribute @crans_attribute
@ -1260,6 +1237,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]
ldap_name = "prise" ldap_name = "prise"
@crans_attribute @crans_attribute
@ -1369,7 +1347,7 @@ class blacklist(Attr):
optional = True optional = True
legend = u"Blackliste" legend = u"Blackliste"
category = 'info' category = 'info'
can_modify = [nounou, bureau] can_modify = [nounou]
ldap_name = "blacklist" ldap_name = "blacklist"
python_type = dict python_type = dict
@ -1482,7 +1460,7 @@ class homeDirectory(rightProtectedAttr):
ldap_name = "homeDirectory" ldap_name = "homeDirectory"
@crans_attribute @crans_attribute
class loginShell(rightProtectedAttr): class loginShell(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
@ -1499,7 +1477,7 @@ class loginShell(rightProtectedAttr):
self.value = shell self.value = shell
@crans_attribute @crans_attribute
class uidNumber(intAttr, rightProtectedAttr): class uidNumber(intAttr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
@ -1507,17 +1485,15 @@ class uidNumber(intAttr, rightProtectedAttr):
legend = "L'uid du compte de l'adherent" legend = "L'uid du compte de l'adherent"
category = 'id' category = 'id'
ldap_name = "uidNumber" ldap_name = "uidNumber"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class gidNumber(intAttr, rightProtectedAttr): class gidNumber(intAttr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = True optional = True
legend = "Le gid du compte de l'adhérent" legend = "Le gid du compte de l'adhérent"
category = 'id' category = 'id'
ldap_name = "gidNumber" ldap_name = "gidNumber"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class gecos(Attr): class gecos(Attr):
@ -1527,7 +1503,6 @@ class gecos(Attr):
legend = "Le gecos" legend = "Le gecos"
category = 'id' category = 'id'
ldap_name = "gecos" ldap_name = "gecos"
can_modify = [cableur, nounou]
@crans_attribute @crans_attribute
class userPassword(rightProtectedAttr): class userPassword(rightProtectedAttr):
@ -1620,7 +1595,6 @@ class gpgMail(mail):
legend = "Mail associé à une clef gpg" legend = "Mail associé à une clef gpg"
can_modify = [soi, nounou] can_modify = [soi, nounou]
ldap_name = "gpgMail" ldap_name = "gpgMail"
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
super(mail, self).check_uniqueness(liste_exclue) super(mail, self).check_uniqueness(liste_exclue)
@ -1633,7 +1607,6 @@ class cn(Attr):
__slots__ = () __slots__ = ()
singlevalue = True singlevalue = True
optional = False optional = False
can_modify = [cableur, nounou]
category = 'id' category = 'id'
ldap_name = "cn" ldap_name = "cn"
@ -1696,7 +1669,7 @@ class modePaiement(Attr):
self.value = mode self.value = mode
@crans_attribute @crans_attribute
class recuPaiement(generalizedTimeFormat): class recuPaiement(Attr):
__slots__ = () __slots__ = ()
ldap_name = "recuPaiement" ldap_name = "recuPaiement"
can_modify = [cableur, nounou] can_modify = [cableur, nounou]
@ -1766,6 +1739,7 @@ class machineAlias(boolAttr):
class issuerCN(Attr): class issuerCN(Attr):
__slots__ = () __slots__ = ()
ldap_name = "issuerCN" ldap_name = "issuerCN"
can_modify = [nounou]
legend = "Common Name de l'éméteur du certificat" legend = "Common Name de l'éméteur du certificat"
@crans_attribute @crans_attribute
@ -1773,18 +1747,21 @@ class serialNumber(Attr):
__slots__ = () __slots__ = ()
ldap_name = "serialNumber" ldap_name = "serialNumber"
python_type = int python_type = int
can_modify = [nounou]
legend = "Numéro de série du certificat" legend = "Numéro de série du certificat"
@crans_attribute @crans_attribute
class start(intAttr): class start(intAttr):
__slots__ = () __slots__ = ()
ldap_name = "start" ldap_name = "start"
can_modify = [nounou]
legend = "Date de début" legend = "Date de début"
@crans_attribute @crans_attribute
class end(intAttr): class end(intAttr):
__slots__ = () __slots__ = ()
ldap_name = "end" ldap_name = "end"
can_modify = [nounou]
legend = "Date de fin" legend = "Date de fin"
@crans_attribute @crans_attribute
@ -1801,6 +1778,7 @@ class revocked(boolAttr):
ldap_name = "revocked" ldap_name = "revocked"
singlevalue = True singlevalue = True
optional = True optional = True
can_modify = [nounou]
legend = "Détermine si le certificat est révoqué" legend = "Détermine si le certificat est révoqué"
@crans_attribute @crans_attribute

View file

@ -47,6 +47,7 @@ if '/usr/scripts' not in sys.path:
sys.path.append('/usr/scripts') sys.path.append('/usr/scripts')
from gestion import config from gestion import config
from unicodedata import normalize from unicodedata import normalize
import subprocess
from netifaces import interfaces, ifaddresses, AF_INET from netifaces import interfaces, ifaddresses, AF_INET
try: try:
@ -54,11 +55,6 @@ try:
except: except:
pytz = None pytz = None
try:
import dateutil.tz
except:
dateutil = None
DEVNULL = open(os.devnull, 'w') DEVNULL = open(os.devnull, 'w')
def find_rid_plage(rid): def find_rid_plage(rid):
@ -249,6 +245,7 @@ def escape(chaine):
dans une requête ldap.""" dans une requête ldap."""
return ldap.filter.escape_filter_chars(chaine) return ldap.filter.escape_filter_chars(chaine)
def hash_password(password, salt=None, longueur=4): def hash_password(password, salt=None, longueur=4):
if longueur < 4: if longueur < 4:
raise ValueError("salt devrait faire au moins 4 octets") raise ValueError("salt devrait faire au moins 4 octets")
@ -344,57 +341,21 @@ def from_generalized_time_format(gtf):
""" """
return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S")) return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S"))
def localized_datetime(date=None, tz=None):
"""Builds a datetime object based on a date string formatted as
%Y%m%d%H%M%S, and a tz timezone looking like +0200"""
if tz is None:
if date is not None:
if "+" in date or '-' in date or 'Z' in date:
if date.endswith("Z"):
date = date[:-1] + "+0000"
date, tz = date[:-5], date[-5:]
_notz = (tz is None)
# Shit may happen
if tz == "Z":
tz = "+0000"
if date is not None:
the_date = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
else:
the_date = datetime.datetime.now()
# No timezone means we try to get from the system
# if we have dateutil, else, UTC.
if tz is None:
if dateutil is not None:
tz = datetime.datetime.now(dateutil.tz.tzlocal()).strftime("%z")
else:
tz = "+0000"
# No pytz means no timezoned datetime
if pytz is not None:
the_timezone = pytz.FixedOffset(int(tz[0:-2])*60 + int(tz[-2:]))
the_date = the_timezone.localize(the_date)
the_date = the_timezone.normalize(the_date)
else:
# Maybe we can do something
if dateutil is not None:
if _notz:
the_date.replace(tzinfo=dateutil.tz.tzlocal())
return the_date
def datetime_from_generalized_time_format(gtf): def datetime_from_generalized_time_format(gtf):
"""Returns a datetime from generalized time format""" """Returns a datetime from generalized time format
"""
if '-' in gtf or '+' in gtf: if '-' in gtf or '+' in gtf:
date, tz = gtf[0:14], gtf[14:] date, tz = gtf[0:14], gtf[14:]
else: else:
date = gtf.replace("Z", '') date = gtf.replace("Z", '')
tz = '+0000' tz = '+0000'
return localized_datetime(date, tz) the_date = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
if pytz is not None:
the_timezone = pytz.FixedOffset(int(tz[0:-2])*60 + int(tz[-2:]))
the_date = the_timezone.localize(the_date)
the_date = the_timezone.normalize(the_date)
return the_date
def datetime_to_generalized_time_format(datetime_obj): def datetime_to_generalized_time_format(datetime_obj):
"""Transforms a datetime to a GTF""" """Transforms a datetime to a GTF"""

View file

@ -1,3 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# LC_LDAP.PY-- LightWeight CransLdap # LC_LDAP.PY-- LightWeight CransLdap
@ -38,7 +39,6 @@
import os import os
import sys import sys
import re import re
import time
from contextlib import contextmanager from contextlib import contextmanager
import ldap import ldap
@ -53,12 +53,11 @@ import variables
import copy import copy
import itertools import itertools
## import de /usr/scripts ## import de /usr/scripts/
if "/usr/scripts" not in sys.path: if not "/usr/scripts/" in sys.path:
sys.path.append('/usr/scripts') sys.path.append('/usr/scripts/')
import gestion.config as config import gestion.config as config
from gestion import secrets_new as secrets
import cranslib.deprecated import cranslib.deprecated
# A priori, ldif_to_uldif et ldif_to_cldif sont obsolètes, # A priori, ldif_to_uldif et ldif_to_cldif sont obsolètes,
@ -106,10 +105,6 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
# Si un username, on récupère le dn associé… # Si un username, on récupère le dn associé…
if user and not dn: if user and not dn:
if readonly_dn is None:
readonly_dn = secrets.get('ldap_readonly_auth_dn')
if readonly_password is None:
readonly_password = secrets.get('ldap_readonly_password')
dn = self.user_to_dn(user, readonly_dn, readonly_password) dn = self.user_to_dn(user, readonly_dn, readonly_password)
# 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
@ -117,7 +112,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
if dn: if dn:
self.conn = self.bind_s(dn, cred) self.conn = self.bind_s(dn, cred)
self.dn = dn self.dn = dn
self.droits = [droit.decode(config.ldap_encoding) for droit in 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', [])
if dn == variables.admin_dn: if dn == variables.admin_dn:
self.droits += [attributs.nounou] self.droits += [attributs.nounou]
# Il faut peupler current_login, qui sera utilisé pour écrire dans l'historique qui fait des modifications # Il faut peupler current_login, qui sera utilisé pour écrire dans l'historique qui fait des modifications
@ -252,7 +247,6 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
res = {} res = {}
parent = {} parent = {}
machines = {} machines = {}
factures = {}
# (proxying de la base ldap) # (proxying de la base ldap)
for dn, attrs in self.search_s(variables.base_dn, scope=2): for dn, attrs in self.search_s(variables.base_dn, scope=2):
# On crée les listes des machines et propriétaires # On crée les listes des machines et propriétaires
@ -262,26 +256,14 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
if not machines.has_key(parent_dn): if not machines.has_key(parent_dn):
machines[parent_dn] = [] machines[parent_dn] = []
machines[parent_dn].append(m) machines[parent_dn].append(m)
if dn.startswith('fid='): # les factures
f = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs))
parent_dn = dn.split(',', 1)[1]
if not factures.has_key(parent_dn):
factures[parent_dn] = []
factures[parent_dn].append(f)
elif (dn.startswith('aid=') or dn.startswith('cid=') or dn == variables.base_dn) and not parent.has_key(dn): elif (dn.startswith('aid=') or dn.startswith('cid=') or dn == variables.base_dn) and not parent.has_key(dn):
parent[dn] = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs)) parent[dn] = objets.new_cransldapobject(self, dn, mode, uldif=ldif_to_uldif(attrs))
allmachines = [] allmachines = []
for dn in parent: # on associe propriétaires et factures, machines for dn, mlist in machines.iteritems(): # on associe propriétaires et machines
mlist = machines.get(dn, [])
flist = factures.get(dn, [])
parent[dn]._machines = mlist parent[dn]._machines = mlist
parent[dn]._factures = flist
parent[dn]._factures_last_update = time.time()
for m in mlist: for m in mlist:
m._proprio = parent[dn] m._proprio = parent[dn]
allmachines.append(m) allmachines.append(m)
for f in flist:
f._proprio = parent[dn]
return allmachines, parent.values() # on renvoie la liste des machines et des adherents (dont club et crans) return allmachines, parent.values() # on renvoie la liste des machines et des adherents (dont club et crans)
def allMachines(self, mode='ro'): def allMachines(self, mode='ro'):
@ -329,7 +311,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object):
uldif['objectClass'] = [u'machineCrans'] uldif['objectClass'] = [u'machineCrans']
assert isinstance(owner, objets.AssociationCrans) assert isinstance(owner, objets.AssociationCrans)
elif realm in ["bornes", "bornes-v6"]: elif realm == "bornes":
uldif['objectClass'] = [u'borneWifi'] uldif['objectClass'] = [u'borneWifi']
assert isinstance(owner, objets.AssociationCrans) assert isinstance(owner, objets.AssociationCrans)

View file

@ -179,7 +179,7 @@ class LdapLockHolder:
host, pid, begin = self.getlock(item, value) host, pid, begin = self.getlock(item, value)
time_left = self.timeout - (time.time() - begin) time_left = self.timeout - (time.time() - begin)
if time_left <= delai: if time_left <= delai:
raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value)) raise LockExpired("Le lock sur la donnée %r=%r à expiré" % (item, value, time_left))
def removelock(self, item, value, Id='default', force=False): def removelock(self, item, value, Id='default', force=False):
""" """
@ -214,3 +214,6 @@ class LdapLockHolder:
except ldap.INVALID_DN_SYNTAX: except ldap.INVALID_DN_SYNTAX:
print '%s=%s,%s' % (item, value, LOCKS_DN) print '%s=%s,%s' % (item, value, LOCKS_DN)
raise raise
except ValueError as e:
self.removelock(item, value, Id, force=True)
raise LockNotFound()

602
objets.py

File diff suppressed because it is too large Load diff

View file

@ -3,17 +3,13 @@
{{["aid=",o.aid.0]|join|coul('bleu')}} {{"Nom : "|coul('gras')}}{{o.prenom|join(' ')}} {{o.nom|join(' ')}} {{["aid=",o.aid.0]|join|coul('bleu')}} {{"Nom : "|coul('gras')}}{{o.prenom|join(' ')}} {{o.nom|join(' ')}}
{% endblock%} {% endblock%}
{% block proprio %} {% block proprio %}
{% if disp_telephone %}
{{"Numéro de téléphone : "|coul('gras')}}{{o.tel|telephone|join(', ')}} {{"Numéro de téléphone : "|coul('gras')}}{{o.tel|telephone|join(', ')}}
{% endif %}
{% if disp_adresse %}
{% if o.chbre.0 == 'EXT' and o.postalAddress %} {% if o.chbre.0 == 'EXT' and o.postalAddress %}
{{"Adresse : "|coul('gras')}}{{o.postalAddress.0}} {{o.postalAddress.1}} {{"Adresse : "|coul('gras')}}{{o.postalAddress.0}} {{o.postalAddress.1}}
{{o.postalAddress.2}} {{o.postalAddress.3}} {{o.postalAddress.2}} {{o.postalAddress.3}}
{% else %} {% else %}
{{"Chambre : "|coul('gras')}}{{o.chbre.0}} ({{o.chbre.0|string|prise_etat}}) {{"Chambre : "|coul('gras')}}{{o.chbre.0}} ({{o.chbre.0|string|prise_etat}})
{% endif %} {% endif %}
{% endif %}
{{"Études : "|coul('gras')}}{{o.etudes|join(' ')}} {{"Études : "|coul('gras')}}{{o.etudes|join(' ')}}
{{adh}} {% if o.get('controle', []) and 'p' in o.controle.0.value %}{{"(OK)"|coul('vert')}}{% endif %} {{adh}} {% if o.get('controle', []) and 'p' in o.controle.0.value %}{{"(OK)"|coul('vert')}}{% endif %}

View file

@ -1,4 +1,4 @@
{{["fid=",o.oid().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio().oid().0}}) {{["fid=",o._id().0]|join|coul('bleu')}} {{"À : "|coul('gras')}}{{o.proprio().prenom|join(' ')}} {{o.proprio().nom|join(' ')}} ({{o.proprio()._id().0}})
{% if o.article %} {% if o.article %}
{{"Article : "|coul('gras')}} Prix N° Total Commentaire {{"Article : "|coul('gras')}} Prix N° Total Commentaire
{% set total = [] %}{% for a in o.article %} {% set total = [] %}{% for a in o.article %}

View file

@ -6,9 +6,6 @@
{{"IPv4 : "|coul('gras')}}{{o.ipHostNumber|join(', ')}} {{"IPv4 : "|coul('gras')}}{{o.ipHostNumber|join(', ')}}
{% if o.ip6HostNumber %}{{"IPv6 : "|coul('gras')}}{{o.ip6HostNumber|join(', ')}} {% if o.ip6HostNumber %}{{"IPv6 : "|coul('gras')}}{{o.ip6HostNumber|join(', ')}}
{% endif %} {% endif %}
{% if sshfp and o.sshFingerprint %}
{{"Fingerprints SSH : "|coul('gras')}}{{o.sshFingerprint|join('\n ')}}
{% endif %}
{{"DnsIpv6 : "|coul('gras')}}{% if not o.dnsIpv6 or o.dnsIpv6.0.value %} {{"DnsIpv6 : "|coul('gras')}}{% if not o.dnsIpv6 or o.dnsIpv6.0.value %}
{{"TRUE"|coul('vert')}} {{"TRUE"|coul('vert')}}
{% else %} {% else %}

View file

@ -16,7 +16,6 @@ import gestion.annuaires_pg
import gestion.hptools2 as hptools2 import gestion.hptools2 as hptools2
import lc_ldap.attributs as attributs import lc_ldap.attributs as attributs
import lc_ldap.crans_utils as crans_utils
def try_import(lib): def try_import(lib):
""" """
@ -202,21 +201,16 @@ def list_factures(factures, width=None):
data = [] data = []
for facture in factures: for facture in factures:
controle = facture.get('controle', [""])[0] controle = facture.get('controle', [""])[0]
if controle == u"TRUE": if controle == "TRUE":
controle = style(u"Validée", "vert") controle = style(u"Validée", "vert")
elif controle == u"FALSE": elif controle == "FALSE":
controle = style(u"Invalide", "rouge") controle = style(u"Invalide", "rouge")
else: else:
controle = u"N/A" controle = u"N/A"
if facture.get('recuPaiement', []):
_dtime = crans_utils.datetime_from_generalized_time_format(unicode(facture.get('recuPaiement', [attributs.recuPaiement.default])[0]))
_recu = _dtime.strftime("%d/%m/%Y %H:%M:%S")
else:
_recu = False
data.append([ data.append([
facture['fid'][0], facture['fid'][0],
facture['modePaiement'][0], facture['modePaiement'][0],
style(_recu, 'vert') if _recu else style(u"NON", 'rouge'), style(facture.get('recuPaiement', [])[0], "vert") if facture.get('recuPaiement', []) else style("NON", "rouge"),
controle, controle,
' '.join(attr['code'] for attr in facture.get('article',[])), ' '.join(attr['code'] for attr in facture.get('article',[])),
u"%s €" % sum([float(a['pu'])*int(a['nombre']) for a in facture.get('article',[])]) u"%s €" % sum([float(a['pu'])*int(a['nombre']) for a in facture.get('article',[])])
@ -229,69 +223,49 @@ def list_factures(factures, width=None):
width=width) width=width)
def list_adherents(adherents, width=None): def list_adherents(adherents, width=None):
return tableau( return tableau([
[ [a['aid'][0],
[ u' '.join(unicode(i) for i in a['prenom'] + a['nom']),
a['aid'][0], a['chbre'][0], style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'),
u' '.join(unicode(i) for i in a['prenom'] + a['nom']), u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines())
a['chbre'][0], ] for a in adherents ],
style('o', 'vert') if a.adhesion_ok() else style('n', 'rouge'), titre = [u'aid', u'Prénom Nom', u'Chbre', u'P', u'Machines'],
style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'), largeur = [5, 35, 5, 1, '*'],
u', '.join(unicode(m['host'][0]).split('.', 1)[0] for m in a.machines()) alignement = ['d', 'c', 'c', 'c', 'g'],
] width=width)
for a in adherents
],
titre=[u'aid', u'Prénom Nom', u'Chbre', u'A', u'C', u'Machines'],
largeur=[5, 35, 5, 1, 1, '*'],
alignement=['d', 'c', 'c', 'c', 'c', 'g'],
width=width
)
def list_clubs(clubs, width=None): def list_clubs(clubs, width=None):
return tableau( return tableau([
[ [a['cid'][0],
[ u' '.join(unicode(i) for i in a['nom']),
a['cid'][0], a['chbre'][0], style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'),
u' '.join(unicode(i) for i in a['nom']), u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines())
a['chbre'][0], ] for a in clubs ],
style('o', 'vert') if a.adhesion_ok() else style('n', 'rouge'), titre = [u'cid', u'Nom', u'Chbre', u'P', u'Machines'],
style('o', 'vert') if a.paiement_ok() else style('n', 'rouge'), largeur = [5, 35, 5, 1, '*'],
u', '.join(unicode(m['host'][0]).split('.',1)[0] for m in a.machines()) alignement = ['d', 'c', 'c', 'c', 'g'],
] width=width)
for a in clubs
],
titre = [u'cid', u'Nom', u'Chbre', u'A', u'C', u'Machines'],
largeur = [5, 35, 5, 1, 1, '*'],
alignement = ['d', 'c', 'c', 'c', 'c', 'g'],
width=width
)
def proprio(proprio, params): def proprio(proprio, params):
_now = crans_utils.localized_datetime() params['o']=proprio
params['o'] = proprio etat_administratif=[]
etat_administratif = []
if proprio.paiement_ok(): if proprio.paiement_ok():
etat_administratif.append(style(u"à jour", "vert")) etat_administratif.append(style(u"à jour", "vert"))
if not proprio.paiement_ok(): if not proprio.paiement_ok():
etat_administratif.append(style(u"cotisation non réglée", "violet")) etat_administratif.append(style(u"cotisation non réglée", "violet"))
if proprio.fin_adhesion() >= time.time():
if proprio.fin_adhesion() >= _now:
adh = style(u"Adhésion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_adhesion())),), "vert") adh = style(u"Adhésion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_adhesion())),), "vert")
elif proprio.paiement_ok(): elif proprio.paiement_ok():
adh = style(u"Adhésion terminée, mais il y a un sursis.", 'orange') adh = style(u"Adhésion terminée, mais il y a un sursis.", 'orange')
else: else:
adh = style(u"Pas adhérent actuellement.", 'rouge') adh = style(u"Pas adhérent actuellement.", 'rouge')
params["adh"] = adh params["adh"] = adh
if proprio.fin_connexion() >= _now: if proprio.fin_connexion() >= time.time():
conn = style(u"Connexion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_connexion())),), "vert") conn = style(u"Connexion jusqu'au %s" % (time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(proprio.fin_connexion())),), "vert")
elif proprio.paiement_ok(): elif proprio.paiement_ok():
conn = style(u"Connexion terminée, mais il y a un sursis.", 'orange') conn = style(u"Connexion terminée, mais il y a un sursis.", 'orange')
else: else:
conn = style(u"Pas connecté actuellement.", 'rouge') conn = style(u"Pas connecté actuellement.", 'rouge')
params["conn"] = conn params["conn"] = conn
params['etat_administratif'] = etat_administratif params['etat_administratif'] = etat_administratif
@ -324,10 +298,7 @@ def blacklist(blacklist, params):
def sprint(object, historique=5, blacklist_len=5, **params): def sprint(object, historique=5, blacklist_len=5, **params):
from lc_ldap import objets, attributs from lc_ldap import objets, attributs
params.update({ params.update({'historique':historique, "blacklist":blacklist_len})
'historique': historique,
'blacklist': blacklist_len,
})
if isinstance(object, objets.machine): if isinstance(object, objets.machine):
return machine(object, params) return machine(object, params)
elif isinstance(object, objets.adherent): elif isinstance(object, objets.adherent):

View file

@ -32,6 +32,7 @@ services_to_attrs['mail_modif'] = [ attributs.droits, attributs.exempt ] + servi
services_to_objects={} services_to_objects={}
services_to_objects['delete']={} services_to_objects['delete']={}
services_to_objects['create']={} services_to_objects['create']={}
services_to_objects['create']['home'] = [objets.adherent, objets.club]
services_to_objects['delete']['del_user'] = [objets.adherent, objets.club] services_to_objects['delete']['del_user'] = [objets.adherent, objets.club]
NOW = time.time() NOW = time.time()

View file

@ -15,7 +15,7 @@ try:
from gestion import secrets_new as secrets from gestion import secrets_new as secrets
except ImportError: except ImportError:
sys.stderr.write("lc_ldap shortcuts: shaa, cannot import secrets_new. " + sys.stderr.write("lc_ldap shortcuts: shaa, cannot import secrets_new. " +
"try again with /usr/scripts in PYTHONPATH " + "try again with /usr/scripts/ in PYTHONPATH " +
"(argv: %s)\n" % " ".join(getattr(sys, 'argv', []))) "(argv: %s)\n" % " ".join(getattr(sys, 'argv', [])))
sys.path.append("/usr/scripts") sys.path.append("/usr/scripts")
from gestion import secrets_new as secrets from gestion import secrets_new as secrets
@ -51,7 +51,7 @@ def lc_ldap_test(*args, **kwargs):
except OSError: except OSError:
pass pass
# On impose le serveur # On impose le serveur
kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'vo.adm.crans.org') kwargs["uri"] = 'ldap://%s' % (DB_TEST_OVERRIDE or 'localhost')
kwargs.setdefault("dn", 'cn=admin,dc=crans,dc=org') kwargs.setdefault("dn", 'cn=admin,dc=crans,dc=org')
# Le mot de passe de la base de test # Le mot de passe de la base de test
kwargs.setdefault("cred", variables.ldap_test_password) kwargs.setdefault("cred", variables.ldap_test_password)

View file

@ -14,6 +14,8 @@ import lc_ldap
import shortcuts import shortcuts
import variables import variables
## import dans /usr/scripts/
sys.path.append("/usr/scripts/")
from gestion.affich_tools import anim, OK, cprint, ERREUR from gestion.affich_tools import anim, OK, cprint, ERREUR
mail_format = False mail_format = False