Table des matières

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 :

<VirtualHost *:80>
    ServerName re2o.federez.net
    ServerAlias re2o webldap webldap.federez.net

    Redirect "/" "https://re2o.federez.net/"    

</VirtualHost>

<VirtualHost *:443>
    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

</VirtualHost>

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)