From 169e31259634ef10454500b318ebf75e8fd46dea Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 2 May 2024 11:52:41 -0400 Subject: [PATCH] Move the modified _mirror_groups() method to a separate module to retain license --- .../__init__.py} | 46 +------------ netbox/netbox/authentication/misc.py | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+), 43 deletions(-) rename netbox/netbox/{authentication.py => authentication/__init__.py} (90%) create mode 100644 netbox/netbox/authentication/misc.py diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication/__init__.py similarity index 90% rename from netbox/netbox/authentication.py rename to netbox/netbox/authentication/__init__.py index eeedb22c2..4912d8b31 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication/__init__.py @@ -10,10 +10,11 @@ from django.db.models import Q from django.utils.translation import gettext_lazy as _ from users.constants import CONSTRAINT_TOKEN_USER -from users.models import Group, ObjectPermission +from users.models import ObjectPermission from utilities.permissions import ( permission_is_exempt, qs_filter_from_constraints, resolve_permission, resolve_permission_type, ) +from .misc import _mirror_groups UserModel = get_user_model() @@ -325,48 +326,7 @@ try: permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) return permission_filter - # Monkey-patch _mirror_groups, code is from django-auth-ldap.backends._LDAPUser - # There are no changes to this routine, the 'fix' is the import of Group above. - def _mirror_groups(self): - """ - Mirrors the user's LDAP groups in the Django database and updates the - user's membership. - """ - target_group_names = frozenset(self._get_groups().get_group_names()) - current_group_names = frozenset( - self._user.groups.values_list("name", flat=True).iterator() - ) - - # These were normalized to sets above. - MIRROR_GROUPS_EXCEPT = self.settings.MIRROR_GROUPS_EXCEPT - MIRROR_GROUPS = self.settings.MIRROR_GROUPS - - # If the settings are white- or black-listing groups, we'll update - # target_group_names such that we won't modify the membership of groups - # beyond our purview. - if isinstance(MIRROR_GROUPS_EXCEPT, (set, frozenset)): - target_group_names = (target_group_names - MIRROR_GROUPS_EXCEPT) | ( - current_group_names & MIRROR_GROUPS_EXCEPT - ) - elif isinstance(MIRROR_GROUPS, (set, frozenset)): - target_group_names = (target_group_names & MIRROR_GROUPS) | ( - current_group_names - MIRROR_GROUPS - ) - - if target_group_names != current_group_names: - existing_groups = list( - Group.objects.filter(name__in=target_group_names).iterator() - ) - existing_group_names = frozenset(group.name for group in existing_groups) - - new_groups = [ - Group.objects.get_or_create(name=name)[0] - for name in target_group_names - if name not in existing_group_names - ] - - self._user.groups.set(existing_groups + new_groups) - + # Patch with our modified _mirror_groups() method to support our custom Group model _LDAPUser._mirror_groups = _mirror_groups except ModuleNotFoundError: diff --git a/netbox/netbox/authentication/misc.py b/netbox/netbox/authentication/misc.py new file mode 100644 index 000000000..fe89b8e39 --- /dev/null +++ b/netbox/netbox/authentication/misc.py @@ -0,0 +1,67 @@ +# Copyright (c) 2009, Peter Sagerson +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# - Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from users.models import Group + + +# Copied from django_auth_ldap.backend._LDAPUser and modified to support our +# custom Group model. +def _mirror_groups(self): + """ + Mirrors the user's LDAP groups in the Django database and updates the + user's membership. + """ + target_group_names = frozenset(self._get_groups().get_group_names()) + current_group_names = frozenset( + self._user.groups.values_list("name", flat=True).iterator() + ) + + # These were normalized to sets above. + MIRROR_GROUPS_EXCEPT = self.settings.MIRROR_GROUPS_EXCEPT + MIRROR_GROUPS = self.settings.MIRROR_GROUPS + + # If the settings are white- or black-listing groups, we'll update + # target_group_names such that we won't modify the membership of groups + # beyond our purview. + if isinstance(MIRROR_GROUPS_EXCEPT, (set, frozenset)): + target_group_names = (target_group_names - MIRROR_GROUPS_EXCEPT) | ( + current_group_names & MIRROR_GROUPS_EXCEPT + ) + elif isinstance(MIRROR_GROUPS, (set, frozenset)): + target_group_names = (target_group_names & MIRROR_GROUPS) | ( + current_group_names - MIRROR_GROUPS + ) + + if target_group_names != current_group_names: + existing_groups = list( + Group.objects.filter(name__in=target_group_names).iterator() + ) + existing_group_names = frozenset(group.name for group in existing_groups) + + new_groups = [ + Group.objects.get_or_create(name=name)[0] + for name in target_group_names + if name not in existing_group_names + ] + + self._user.groups.set(existing_groups + new_groups)