From 5706e9064ebffe9f0e1d4e8eb72644524ecaa355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Sun, 29 Apr 2018 14:37:18 +0000 Subject: [PATCH 1/3] Fix #117 : Use unix_name instead of name for ldap groups A group in the LDAP now use the `unix_name` instead of the `name` The `new_group` form has now a more logical order for the fields The label for the `unix_name` is now more explicit --- users/forms.py | 13 +++++++------ users/models.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/users/forms.py b/users/forms.py index 8c6f5db9..670fbb98 100644 --- a/users/forms.py +++ b/users/forms.py @@ -501,7 +501,7 @@ class ShellForm(FormRevMixin, ModelForm): class ListRightForm(FormRevMixin, ModelForm): """Edition, d'un groupe , équivalent à un droit - Ne peremet pas d'editer le gid, car il sert de primary key""" + Ne permet pas d'editer le gid, car il sert de primary key""" permissions = forms.ModelMultipleChoiceField( Permission.objects.all().select_related('content_type'), widget=forms.CheckboxSelectMultiple, @@ -510,23 +510,24 @@ class ListRightForm(FormRevMixin, ModelForm): class Meta: model = ListRight - fields = ['name', 'unix_name', 'critical', 'permissions', 'details'] + fields = ('name', 'unix_name', 'critical', 'permissions', 'details') def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['unix_name'].label = 'Nom du droit/groupe' + self.fields['unix_name'].label = 'Nom UNIX du groupe' class NewListRightForm(ListRightForm): """Ajout d'un groupe/list de droit """ class Meta(ListRightForm.Meta): - fields = '__all__' + fields = ('name', 'unix_name', 'gid', 'critical', 'permissions', + 'details') def __init__(self, *args, **kwargs): super(NewListRightForm, self).__init__(*args, **kwargs) - self.fields['gid'].label = 'Gid, attention, cet attribut ne doit\ - pas être modifié après création' + self.fields['gid'].label = ("Gid, attention, cet attribut ne doit " + "pas être modifié après création") class DelListRightForm(Form): diff --git a/users/models.py b/users/models.py index d0e21997..0284985c 100644 --- a/users/models.py +++ b/users/models.py @@ -1175,7 +1175,7 @@ class ListRight(RevMixin, AclMixin, Group): group_ldap = LdapUserGroup.objects.get(gid=self.gid) except LdapUserGroup.DoesNotExist: group_ldap = LdapUserGroup(gid=self.gid) - group_ldap.name = self.listright + group_ldap.name = self.unix_name group_ldap.members = [user.pseudo for user in self.user_set.all()] group_ldap.save() From 05a53b1c9c62659b65a67ef4b01845a2b3887a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Mon, 28 May 2018 10:19:59 +0000 Subject: [PATCH 2/3] Add reload to do in CHANGELOG --- CHANGELOG.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b9b8ca..9e08597f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## MR 160: Datepicker Install libjs-jquery libjs-jquery-ui libjs-jquery-timepicker libjs-bootstrap javascript-common -``` +```bash apt-get -y install \ libjs-jquery \ libjs-jquery-ui \ @@ -10,12 +10,12 @@ apt-get -y install \ javascript-common ``` Enable javascript-common conf -``` +```bash a2enconf javascript-common ``` Delete old jquery files : -``` +```bash rm -r static_files/js/jquery-ui-* rm static_files/js/jquery-2.2.4.min.js rm static/css/jquery-ui-timepicker-addon.css @@ -42,6 +42,7 @@ Refactored install_re2o.sh script. ``` install_re2o.sh help ``` + * The installation templates (LDIF files and `re2o/settings_locale.example.py`) have been changed to use `example.net` instead of `example.org` (more neutral and generic) @@ -75,7 +76,6 @@ OPTIONAL_APPS = ( ``` - ## MR 177: Add django-debug-toolbar support Add the possibility to enable `django-debug-toolbar` in debug mode. First install the APT package: @@ -94,3 +94,26 @@ If you to restrict the IP which can see the debug, use the `INTERNAL_IPS` option ``` INTERNAL_IPS = ["10.0.0.1", "10.0.0.2"] ``` + + +## MR 145: Fix #117 : Use unix_name instead of name for ldap groups + +Fix a mixing between unix_name and name for groups +After this modification you need to: +* Double-check your defined groups' unix-name only contain small letters +* Run the following commands to rebuild your ldap's groups: + ```shell + # In the LDAP shell : + ou=groups,ou=posix > rm * + ``` + ```python + # In the Django shell + >>> from users.model import ListRight + >>> for lr in ListRight.objects.all(): + ... lr.ldap_sync() + ``` + +* You may need to force your nslcd cache to be reloaded on some servers (else you will have to wait for the cache to be refreshed): + ```bash + sudo nslcd -i groups + ``` From 4cbb05d29400ac9f728d7989c5e969b892ce3950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Sat, 7 Jul 2018 18:01:04 +0000 Subject: [PATCH 3/3] Add a Django command to fully rebuild the LDAP --- CHANGELOG.md | 9 +-- users/management/commands/ldap_rebuild.py | 98 +++++++++++++++++++++++ 2 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 users/management/commands/ldap_rebuild.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e08597f..ceb56d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,14 +103,7 @@ After this modification you need to: * Double-check your defined groups' unix-name only contain small letters * Run the following commands to rebuild your ldap's groups: ```shell - # In the LDAP shell : - ou=groups,ou=posix > rm * - ``` - ```python - # In the Django shell - >>> from users.model import ListRight - >>> for lr in ListRight.objects.all(): - ... lr.ldap_sync() + python3 manage.py ldap_rebuild ``` * You may need to force your nslcd cache to be reloaded on some servers (else you will have to wait for the cache to be refreshed): diff --git a/users/management/commands/ldap_rebuild.py b/users/management/commands/ldap_rebuild.py new file mode 100644 index 00000000..a386b080 --- /dev/null +++ b/users/management/commands/ldap_rebuild.py @@ -0,0 +1,98 @@ +# Copyright © 2018 Maël Kervella +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import subprocess +from base64 import decodebytes + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from users.models import User, ListRight + + +def flush_ldap(binddn, bindpass, server, usersdn, groupsdn): + """ + Perform the python (and more understandable) equivalent of the following commands: + + ldapsearch -A -s one -D $binddn -w $bindpass -H $server -b $usersdn dn \ + | grep "dn: " | sed -e 's/dn: //g' \ + | ldapdelete -v -D $binddn -w $bindpass -H $server -- + ldapsearch -A -s one -D $binddn -w $bindpass -H $server -b $usersdn dn \ + | grep "dn:: " | sed -e 's/dn:: //g' \ + | while read x; do echo "$x" | base64 -d; echo ""; done \ + | ldapdelete -v -D $binddn -w $bindpass -H $server -- + ldapsearch -A -s one -D $binddn -w $bindpass -H $server -b $groupsdn dn \ + | grep "dn: " | sed -e 's/dn: //g' \ + | ldapdelete -v -D $binddn -w $bindpass -H $server -- + ldapsearch -A -s one -D $binddn -w $bindpass -H $server -b $groupsdn dn \ + | grep "dn:: " | sed -e 's/dn:: //g' \ + | while read x; do echo "$x" | base64 -d; echo ""; done \ + | ldapdelete -v -D $binddn -w $bindpass -H $server -- + """ + + to_remove = [] + + for lookup in (usersdn, groupsdn): + search_cmd = [ + 'ldapsearch', + '-A', + '-s', 'one', + '-D', binddn, + '-w', bindpass, + '-H', server, + '-b', lookup, + 'dn' + ] + for line in subprocess.check_output(search_cmd).split(b'\n'): + if line.startswith(b'dn: '): + to_remove.append(line[len(b'dn: '):]) + elif line.startswith(b'dn:: '): + # Non ASCII value ares are base64-encoded + to_remove.append(decodebytes(line[len(b'dn:: '):])) + + delete_cmd = [ + 'ldapdelete', + '-D', binddn, + '-w', bindpass, + '-H', server + ] + to_remove + subprocess.check_call(delete_cmd) + + +def sync_ldap(): + """Syncrhonize the whole LDAP with the DB.""" + for u in User.objects.all(): + u.ldap_sync() + for lr in ListRight.objects.all(): + lr.ldap_sync() + + +class Command(BaseCommand): + help = ('Destroy the current LDAP data and rebuild it from the DB data. ' + 'Use with caution.') + + def handle(self, *args, **options): + + usersdn = settings.LDAP['base_user_dn'] + groupsdn = settings.LDAP['base_usergroup_dn'] + binddn = settings.DATABASES['ldap']['USER'] + bindpass = settings.DATABASES['ldap']['PASSWORD'] + server = settings.DATABASES['ldap']['NAME'] + + flush_ldap(binddn, bindpass, server, usersdn, groupsdn) + self.stdout.write("LDAP emptied") + sync_ldap() + self.stdout.write("LDAP rebuilt")