2 # -*- coding: utf-8 -*-
3 """Outil de gestion d'annuaire LDAP pour l'AuF.
5 Copyright ©2009-2010 Agence universitaire de la Francophonie
6 Licence : GPL version 3
7 Auteur : Progfou <jean-christophe.andre@auf.org>
9 Dépendances Debian : python >= 2.5, python-simplejson, auf-refer
13 auf-annuaire.py | ldapmodify -x -c -D "cn=admin,o=AUF" -y /etc/ldap.secret
18 import simplejson as json
20 LDAP_HOST = '127.0.0.1'
21 LDAP_BASE = 'ou=People,o=AUF'
22 LDAP_BINDDN = 'cn=admin,' + LDAP_BASE
23 LDAP_PWFILE = ['~/.ldap.secret', '/etc/ldap.secret']
25 LDAP_INIT_LDIF = u"""dn: ou=People,o=AuF
28 objectClass: organizationalUnit
32 PERSONNELS = aufrefer.get('personnels.json')
33 ISO_3166 = aufrefer.get('iso-3166-fr.json')
34 NOMS_BUREAU = aufrefer.get('bureaux.json')
35 PAYS_IMPLANT = {'IFMT': 'LA', 'DANANG.VN': 'VN'}
37 def capitale_sur_les_mots(s):
39 previous_isalpha = False
42 if isalpha and not previous_isalpha:
45 previous_isalpha = isalpha
48 def pays_implantation(implant):
49 return PAYS_IMPLANT.get(implant.upper(), implant.upper())
51 def nom_pays(country):
52 return ISO_3166.get(country.upper(),
53 u'### Pays absent de la norme ISO-3166 ###')
56 for code, data in NOMS_BUREAU.items():
57 if cc.upper() in data[1]:
59 return u'### implantation inconnue ###', u'### implantation inconnue ###'
61 def login_nom_personnel(adel):
62 info = filter(lambda p: p['adel'] == adel, PERSONNELS)
65 return info[0]['login'], info[0]['nom']
67 class LdapEntry(object):
69 'objectClass', 'sn', 'givenName', 'cn', 'ou', 'l', 'mail', 'o',
70 'userPassword', 'telephoneNumber', 'uid',
73 def __init__(self, dn, d=None, **kv):
81 def get(self, attribute):
82 return self.dict.get(attribute, None)
84 def set(self, attribute, value):
85 old_value = self.dict.get(attribute, None)
86 self.dict[attribute] = value
89 def from_ldif(self, ldif):
90 raise RuntimeError('Note implemented')
92 def _to_ldif_line(self, attribute, value):
95 if c < ' ' or 'z' < c:
99 attribute = attribute + ':'
100 if type(value) == unicode:
101 value = value.encode('utf-8')
102 value = value.encode('base64').rstrip('\n')
103 return u'%s: %s' % (attribute, value)
105 def to_ldif(self, changeType=None):
107 ldif.append(self._to_ldif_line(u'dn', self.dn))
109 ldif.append(u'changeType: %s' % changeType)
110 set_keys = set(self.dict.keys())
111 set_attr_order = set(self._attributes_order)
112 for k in set_keys & set_attr_order:
113 for e in self.dict[k]:
114 ldif.append(self._to_ldif_line(k, e))
115 for k in set_keys - set_attr_order:
116 for e in self.dict[k]:
117 ldif.append(self._to_ldif_line(k, e))
119 return '\n'.join(ldif).encode('utf-8')
122 class AnnuaireAuF(object):
124 'adel', 'redir', 'nom', 'mdp', 'implant', 'coda', 'tel_ext', 'tel_ip',
127 def __init__(self, ldap_base):
128 self.ldap_base = ldap_base
131 def json2ldap(self, json_dict):
132 CC = pays_implantation(json_dict['implant'])
133 nom_bureau_court, nom_bureau_long = noms_bureau(CC)
134 adel = json_dict['adel']
135 user, domain = adel.split('@')
136 cn = capitale_sur_les_mots(user)
137 cn = cn.replace('-De-', '-de-').replace('.', ' ')
138 prenom, nom = cn.rsplit(' ', 1)
139 login, nom_affichage = login_nom_personnel(user)
140 if nom_affichage is None:
141 nom_affichage = json_dict['nom'] and json_dict['nom'] or cn
144 ldap_dict['objectClass'] = [
145 u'top', u'person', u'organizationalPerson', u'inetOrgPerson'
147 ldap_dict['sn'] = [ nom ]
148 ldap_dict['givenName'] = [ prenom ]
149 ldap_dict['cn'] = [ nom_affichage ]
150 ldap_dict['ou'] = [ u'People', nom_bureau_court, nom_bureau_long ]
151 ldap_dict['l'] = [ nom_pays(CC) ]
152 ldap_dict['mail'] = [ adel ]
153 ldap_dict['o'] = [ u'AuF', u'Agence universitaire de la Francophonie' ]
154 if json_dict.has_key('mdp') and json_dict['mdp']:
155 ldap_dict['userPassword'] = [ '{CRYPT}' + json_dict['mdp'] ]
156 if json_dict.has_key('tel_ip') and json_dict['tel_ip']:
157 ldap_dict['telephoneNumber'] = [ json_dict['tel_ip'] ]
158 if login is not None and login:
159 ldap_dict['uid'] = [ login ]
160 ldap_dn = u'mail=%s,%s' % (adel, self.ldap_base)
161 return ldap_dn, ldap_dict
165 for json_dict in aufrefer.get('annuaire.json'):
166 ldap_dn, ldap_dict = self.json2ldap(json_dict)
167 self.data.append(LdapEntry(ldap_dn, ldap_dict))
170 ldif = [ LDAP_INIT_LDIF ]
172 ldif.append(d.to_ldif(changeType='add'))
174 return '\n'.join(ldif)
176 def search(self, name):
177 return filter(lambda x: x['adel'].find(name) >= 0, self.data)
179 def update_ldap(self, base=LDAP_BASE,
180 host=LDAP_HOST, binddn=LDAP_BINDDN, pwfile=LDAP_PWFILE):
183 if __name__ == '__main__':
184 annuaire = AnnuaireAuF(LDAP_BASE)
186 #print "search('andre'): %s" % \
187 # map(lambda x: x['adel'], annuaire.search('andre'))
188 print annuaire.to_ldif(),