Outil de recodage de données PHP sérialisées.
[progfou.git] / openldap / auf-annuaire
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """Outil de gestion d'annuaire LDAP pour l'AuF.
4
5 Copyright ©2009-2010  Agence universitaire de la Francophonie
6 Licence : GPL version 3
7 Auteur : Progfou <jean-christophe.andre@auf.org>
8
9 Dépendances Debian : python >= 2.5, python-simplejson, auf-refer
10
11 Usage :
12
13   auf-annuaire.py | ldapmodify -x -c -D "cn=admin,o=AUF" -y /etc/ldap.secret
14 """
15
16 import os
17 import aufrefer
18 import simplejson as json
19
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']
24
25 LDAP_INIT_LDIF = u"""dn: ou=People,o=AuF
26 changeType: add
27 objectClass: top
28 objectClass: organizationalUnit
29 ou: People
30 """
31
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'}
36
37 def capitale_sur_les_mots(s):
38     r = ''
39     previous_isalpha = False
40     for c in s:
41         isalpha = c.isalpha()
42         if isalpha and not previous_isalpha:
43             c = c.upper()
44         r += c
45         previous_isalpha = isalpha
46     return r
47
48 def pays_implantation(implant):
49     return PAYS_IMPLANT.get(implant.upper(), implant.upper())
50
51 def nom_pays(country):
52     return ISO_3166.get(country.upper(),
53                                 u'### Pays absent de la norme ISO-3166 ###')
54
55 def noms_bureau(cc):
56     for code, data in NOMS_BUREAU.items():
57         if cc.upper() in data[1]:
58             return code, data[0]
59     return u'### implantation inconnue ###', u'### implantation inconnue ###'
60
61 def login_nom_personnel(adel):
62     info = filter(lambda p: p['adel'] == adel, PERSONNELS)
63     if not info:
64         return None, None
65     return info[0]['login'], info[0]['nom']
66
67 class LdapEntry(object):
68     _attributes_order = [
69         'objectClass', 'sn', 'givenName', 'cn', 'ou', 'l', 'mail', 'o',
70         'userPassword', 'telephoneNumber', 'uid',
71     ]
72
73     def __init__(self, dn, d=None, **kv):
74         self.dn = dn
75         if d:
76             self.dict = d
77         else:
78             self.dict = { }
79         self.dict.update(kv)
80
81     def get(self, attribute):
82         return self.dict.get(attribute, None)
83
84     def set(self, attribute, value):
85         old_value = self.dict.get(attribute, None)
86         self.dict[attribute] = value
87         return old_value
88
89     def from_ldif(self, ldif):
90         raise RuntimeError('Note implemented')
91
92     def _to_ldif_line(self, attribute, value):
93         to_encode = False
94         for c in value:
95             if c < ' ' or 'z' < c:
96                 to_encode = True
97                 break
98         if to_encode:
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)
104
105     def to_ldif(self, changeType=None):
106         ldif = [ ]
107         ldif.append(self._to_ldif_line(u'dn', self.dn))
108         if changeType:
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))
118         ldif.append(u'')
119         return '\n'.join(ldif).encode('utf-8')
120
121
122 class AnnuaireAuF(object):
123     _attributes = [
124         'adel', 'redir', 'nom', 'mdp', 'implant', 'coda', 'tel_ext', 'tel_ip',
125     ]
126
127     def __init__(self, ldap_base):
128         self.ldap_base = ldap_base
129         self.data = None
130
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
142
143         ldap_dict = { }
144         ldap_dict['objectClass'] = [
145             u'top', u'person', u'organizationalPerson', u'inetOrgPerson'
146         ]
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
162
163     def load(self):
164         self.data = [ ]
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))
168
169     def to_ldif(self):
170         ldif = [ LDAP_INIT_LDIF ]
171         for d in self.data:
172             ldif.append(d.to_ldif(changeType='add'))
173         ldif.append('')
174         return '\n'.join(ldif)
175
176     def search(self, name):
177         return filter(lambda x: x['adel'].find(name) >= 0, self.data)
178
179     def update_ldap(self, base=LDAP_BASE,
180                     host=LDAP_HOST, binddn=LDAP_BINDDN, pwfile=LDAP_PWFILE):
181         pass
182
183 if __name__ == '__main__':
184     annuaire = AnnuaireAuF(LDAP_BASE)
185     annuaire.load()
186     #print "search('andre'): %s" % \
187     #                    map(lambda x: x['adel'], annuaire.search('andre'))
188     print annuaire.to_ldif(),
189