======== Re2o ========
Soft inter asso de gestion users et reseau. Cf [[https://slides.rezometz.org/re2o.html]]
===== Utilité pour federez =====
L'ancien webldap (en django également) a rendu de très grand services, mais il fallait le maintenir. Autre problème, il n'utilisait pas les models, il fallait tout coder à la main dans les views, ce qui faisait que chaque fonctionnalité nécessitait beaucoup de code.
L'idée d'utiliser une instance de re2O est déjà de ne plus avoir à maintenir un webldap, mais surtout d'avoir plus de fonctionnalités. (gestion des machines de federez, des assos, du dns, etc etc)
===== Instalation =====
==== Démarrage ====
Sur dodecagon :
Suivre le readme.sh; on aurait pu utiliser le script d'install auto, mais on a fait les choses à la main ici.
On clone le dépot [[https://gitlab.federez.net/federez/re2o.git]] dans /var/www/re2o.
On installe toutes les dépendances avec apt et pip3, suivre le readme pour cela :
apt install python3-django python3-dateutil texlive-latex-base texlive-fonts-recommended python3-djangorestframework python3-django-reversion python3-pip libsasl2-dev libldap2-dev libssl-dev
pip3 install django-bootstrap3 django-ldapdb django-macaddress
==== Bdd ====
On choisi mysql en local comme base de donnée django. On initialise la bdd :
apt install python3-mysqldb mysql-client
CREATE DATABASE re2o collate='utf8_general_ci';
CREATE USER 're2o'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON re2o.* TO 're2o'@'localhost';
FLUSH PRIVILEGES;
==== Ldap ====
Vu qu'on migre depuis l'ancien, dans un premier temps on met le ldap sur un autre serveur (federez-test) puis on switchera après. L'installation du ldap est toujours la même, on copie schema.ldiff et db.ldiff depuis le depot.
Ensuite on remplace dans les fichiers dc=example,dc=org par dc=federez, dc=net, ainsi que FILL_IT par le hash du mdp ldap qu'on choisi.
On rajoute le ssl avec
olcTLSCertificateKeyFile: /etc/letsencrypt/live/federez.net/privkey.pem
olcTLSCACertificateFile: /etc/letsencrypt/live/federez.net/chain.pem
olcTLSCertificateFile: /etc/letsencrypt/live/federez.net/cert.pem `
dans schema.db , enfin :
service slapd stop
rm -rf /etc/ldap/slapd.d/*
rm -rf /var/lib/ldap/*
slapadd -n 0 -l schema.ldiff -F /etc/ldap/slapd.d/
slapadd -n 1 -l db.ldiff
chown -R openldap:openldap /etc/ldap/slapd.d
chown -R openldap:openldap /var/lib/ldap
service slapd start
===== Configuration =====
On crée le settings_local.py, à partir de settings_local.example.py. On rempli le mdp bdd et ldap.
On applique les migrations, python3 manage.py migrate, ça prend du temps.
On crée un premier un super user avec python3 manage.py createsuperuser
===== Serveur web =====
On utilise apache, voici la config :
ServerName re2o.federez.net
ServerAlias re2o webldap webldap.federez.net
Redirect "/" "https://re2o.federez.net/"
ServerName re2o.federez.net
ServerAlias re2o webldap webldap.federez.net
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/re2o-error.log
CustomLog ${APACHE_LOG_DIR}/re2o-access.log combined
Alias /static /var/www/re2o/static_files
WSGIScriptAlias / /var/www/re2o/re2o/wsgi.py
WSGIProcessGroup re2o
WSGIDaemonProcess re2o processes=2 threads=16 maximum-requests=1000 display-name=re2o
SSLCertificateFile /etc/letsencrypt/live/federez.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/federez.net/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
On peut à présent se connecter sur re2o.federez.net avec le compte qu'on a crée.
===== Migration depuis l'ancien ldap =====
Les anciennes données étaient dans l'ancien ldap sur dodecagon, il a été nécessaire de transéferer tout le monde.
On utilise python3-ldap3 pour chercher et trouver les informations dans le ldap.
Pour info, voici comment on a procédé :
=== Transfert des users ===
from ldap3 import Server,Connection,ALL_ATTRIBUTES, ALL
conn = Connection(server, 'cn=admin,dc=federez,dc=net', 'pkop', auto_bind=True)
conn.search('ou=users,dc=federez,dc=net', '(objectclass=inetOrgPerson)', attributes=ALL_ATTRIBUTES)
entries = conn.entries
In [79]: from users.models import Adherent, ListShell
In [78]: for en in ent:
...: adh = Adherent()
...: adh.pseudo = str(en.cn)
...: if len(str(en.displayName).split())>1:
...: adh.surname = str(en.displayName).split()[1]
...: adh.name = str(en.displayName).split()[0]
...: else:
...: adh.surname = str(en.displayName)
...: adh.name = str(en.displayName)
...: adh.email = str(en.mail)
...: if hasattr(en, 'loginShell'):
...: adh.shell, created = ListShell.objects.get_or_create(shell=str(en.loginShell))
...: if hasattr(en, 'uidNumber'):
...: adh.uid_number = str(en.uidNumber)
...: if hasattr(en, 'sambaNTPassword'):
...: adh.sambaNTPassword = en.sambaNTPassword
...: if hasattr(en, 'userPassword'):
...: adh.password = str(en.userPassword.value.decode("utf-8")[:6]) + '$' + str(en.userPassword.value.decode("utf-8")[6:])
...: adh.save()
=== Transfert des services-users (bind ldap pour les services) ===
conn.search('ou=service-users,dc=federez,dc=net', '(objectclass=simpleSecurityObject)', attributes=ALL_ATTRIBUTES)
entries = conn.entries
In [87]: for en in entries:
...: s = ServiceUser()
...: s.pseudo = str(en.cn)
...: s.password = str(en.userPassword.value.decode("utf-8")[:6]) + '$' + str(en.userPassword.value.decode("utf-8")[6:])
...: s.save()
=== Transfert des assos ===
A la main, il n'y en avait pas 150
=== Transfert des groupes/liens users-asssos ===
Plus compliqué, il a fallu extraire le pseudo depuis l'objet member of dans les groupes, les jointures n'existant évidemment pas en ldap.
from users.models import User, Adherent, Club
conn.search('ou=associations,dc=federez,dc=net', '(objectclass=groupOfUniqueNames)', attributes=ALL_ATTRIBUTES)
entries = conn.entries
In [1]: for ent in entries:
...: club_instance = Club.objects.get(pseudo=str(ent.o))
...: if hasattr(ent, 'owner'):
...: for own in ent.owner:
...: uid = conn.search('ou=users,dc=federez,dc=net', '(%s)' % str(own.split(',')[0]), attributes=ALL_ATTRIBUTES)
...: user = conn.entries[0]
...: user_instance = Adherent.objects.get(pseudo=str(user.cn))
...: club_instance.administrators.add(user_instance)
...: if hasattr(ent, 'uniqueMember'):
...: for memb in ent.uniqueMember:
...: uid = conn.search('ou=users,dc=federez,dc=net', '(%s)' % str(memb.split(',')[0]), attributes=ALL_ATTRIBUTES)
...: user = conn.entries[0]
...: user_instance = Adherent.objects.get(pseudo=str(user.cn))
...: club_instance.members.add(user_instance)