lc_ldap/attributs.py
2010-10-16 15:46:09 +02:00

328 lines
9.1 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ATTRIBUTS.PY-- Description des attributs ldap
#
# Copyright (C) 2010 Cr@ns <roots@crans.org>
# Author: Antoine Durand-Gasselin <adg@crans.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Cr@ns nor the names of its contributors may
# be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
# HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re
from unicodedata import normalize
def normalize_and_validate(attr, vals, ctxt):
"""Vérifie que attr peut se voir attribuer les valeurs vals"""
a = eval('%s()' % attr)
new_vals = a.normalize(vals, ctxt)
a.validate(new_vals, ctxt)
return new_vals
def validate_name(value, more_chars=""):
"""Valide un nom: ie un unicode qui contient lettres, espaces et
apostrophes, et éventuellement des caractères additionnels"""
return re.match("[A-Za-z][-' A-Za-z%s]*" % more_chars,
normalize('NFKD', value).encode('ASCII', 'ignore'))
def validate_mac(value):
"""Vérifie qu'une adresse mac est valide"""
return True
def attrify(val, attr, ldif, ctxt_check = True):
"""Transforme un n'importe quoi en Attr.
Doit effectuer les normalisations et sanity check si un str ou un
unicode est passé en argument.
Devrait insulter en cas de potentiel problème d'encodage.
Doit effectuer les vérifications de contexte dans le *ldif* si
ctxt_check est vrai"""
if isinstance(val, Attr):
return val
else:
return CRANS_ATTRIBUTES[attr](val, ldif, ctxt_check)
class Attr(object):
legend = "Human-readable description of attribute"
singlevalue = None
optional = None
def __init__(self, val, ldif, ctxt_check):
"""Crée un nouvel objet représentant un attribut.
val: valeur de l'attribut
ldif: objet contenant l'attribut (permet de faire les validations sur l'environnement)
ctxt_check: effectue les validations
"""
self.value = None
assert isinstance(val, unicode)
self.parse_value(val)
if ctxt_check:
self.validate(ldif)
def parse_value(self, val):
"""Transforme l'attribut pour travailler avec notre validateur"""
self.value = val
def __str__(self):
unicode.encode(unicode(self), 'utf-8')
def validate(self, ldif):
"""validates:
vérifie déjà que ce qu'on a rentré est parsable"""
own_values = ldif[self.__class__.__name__]
self._check_cardinality(own_values)
self._check_uniqueness()
self._check_users_restrictions(own_values)
def _check_cardinality(self, values):
"""Vérifie qu'il y a un nombre correct de valeur =1, <=1, {0,1},
etc..."""
if self.singlevalue and len(values) > 1:
raise ValueError(u'%s doit avoir au maximum une valeur (affecte %s)' % self.__class__, values)
if not self.optional and len(values) == 0:
raise ValueError('%s doit avoir au moins une valeur' % self.__class__)
def _check_type(self, values):
"""Vérifie que les valeurs ont le bon type (nom est un mot, tel
est un nombre, etc...)"""
for val in values:
assert isinstance(val, unicode)
def _check_uniqueness(self):
"""Vérifie l'unicité dans la base de la valeur (mailAlias, chbre,
etc...)"""
pass
def _check_values(self, values):
"""Vérifie que les valeurs sont valides (typiquement chbre)"""
pass
def _check_users_restrictions(self, values):
"""Vérifie les restrictions supplémentaires imposées selon les
niveaux de droits (<= 3 mailAlias, pas de mac identiques,
etc...)"""
pass
def can_modify(self):
"""Vérifie si l'attribut est modifiable"""
return False
class objectClass(Attr):
singlevalue = False
optional = False
legend = "entité"
class nom(Attr):
singlevalue = True
optional = False
legend = "Nom"
def _check_type(self, values):
return [ validate_name(v) for v in values]
def normalize(self, values, uldif):
return [ v.strip().capitalize() for v in values ]
class prenom(Attr):
singlevalue = True
optional = False
legend = u"Prénom"
def _check_type(self, values):
return [ validate_name(v) for v in values ]
def normalize(self, values, uldif):
return [ values.strip().capitalize() for v in values ]
class tel(Attr):
singlevalue = True
optional = False
legend = u"Téléphone"
def normalize(self, value, uldif):
return value # XXX - To implement
class paiement(Attr):
singlevallue = False
optional = True
legend = u"Paiement"
def normalize(self, values, uldif):
return values # XXX - To implement
class carteEtudiant(Attr):
singlevalue = False
optional = True
legend = u"Carte d'étudiant"
class mailAlias(Attr):
singlevalue = False
optional = True
legend = u"Alias mail"
class canonicalAlias(Attr):
singlevalue = True
optional = False
legend = u"Alias mail canonique"
class etudes(Attr):
singlevalue = False
optional = False
legend = u"Études"
class chbre(Attr):
singlevalue = True
optional = False
legend = u"Chambre sur le campus"
class droits(Attr):
singlevalue = False
optional = True
legend = u"Droits sur les serveurs"
class solde(Attr):
singlevalue = True
optional = True
legend = u"Solde d'impression"
class host(Attr):
singlevalue = True
optional = False
hname = legend = u"Nom d'hôte"
class macAddress(Attr):
singlevalue = True
optional = False
legend = u"Adresse physique de la carte réseau"
hname = "Adresse MAC"
class ipHostNumber(Attr):
singlevalue = True
optional = False
legend = u"Adresse IPv4 de la machine"
hname = "IPv4"
class mid(Attr):
singlevalue = True
optional = False
legend = "Identifiant de machine"
class hostAlias(Attr):
singlevalue = False
optional = True
legend = u'Alias de nom de machine'
class ipsec(Attr):
singlevalue = False
optional = True
legend = u'Clef wifi'
class puissance(Attr):
singlevalue = True
optional = True
legend = u"puissance d'émission pour les bornes wifi"
class canal(Attr):
singlevalue = True
optional = True
legend = u'Canal d\'émission de la borne'
class portTCPout(Attr):
singlevalue = False
optional = True
legend = u'Port TCP ouvert vers l\'extérieur'
class portTCPin(Attr):
singlevalue = False
optional = True
legend = u"Port TCP ouvert depuis l'extérieur"
class portUDPout(Attr):
singlevalue = False
optional = True
legend = u"Port UDP ouvert vers l'extérieur"
class portUDPin(Attr):
singlevalue = False
optional = True
legend = u"Port UDP ouvert depuis l'extérieur"
class prise(Attr):
singlevalue = True
optional = True
legend = u"Prise sur laquelle est branchée la machine"
class cid(Attr):
singlevalue = True
optional = True
legend = u"Identifiant du club"
class responsable(Attr):
singlevalue = True
optional = True
legend = u"Responsable du club"
class blacklist(Attr):
singlevalue = False
optional = True
legend = u"Blackliste"
class historique(Attr):
singlevalue = False
optional = True
legend = u"Historique de l'objet"
CRANS_ATTRIBUTES= {
'objectClass' : objectClass,
'nom' : nom,
'prenom' : prenom,
'tel' : tel,
'paiement' : paiement,
'carteEtudiant' : carteEtudiant,
'mailAlias' : mailAlias,
'canonicalAlias' : canonicalAlias,
'etudes' : etudes,
'chbre' : chbre,
'droits' : droits,
'solde' : solde,
'mid' : mid,
'hostAlias' : hostAlias,
'ipsec' : ipsec,
'puissance' : puissance,
'canal' : canal,
'portTCPout' : portTCPout,
'portTCPin' : portTCPin,
'portUDPout' : portUDPout,
'portUDPin' : portUDPin,
'prise' : prise,
'cid' : cid,
'responsable' : responsable,
'blacklist' : blacklist,
'historique' : historique
}