From 4fb3a2e0a03918269a2f7c7fb4375ea6c4292a15 Mon Sep 17 00:00:00 2001 From: Hans Erasmus Date: Tue, 22 Jun 2021 09:59:01 +0200 Subject: [PATCH 01/12] Update installation Just separated it so the user can easily click the copy button, and only be presented with the command. --- docs/installation/3-netbox.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 7a8e0bc80..958cd4e46 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -73,6 +73,9 @@ Next, clone the **master** branch of the NetBox GitHub repository into the curre ```no-highlight $ sudo git clone -b master https://github.com/netbox-community/netbox.git . +``` +The screen below should be the result: +``` Cloning into '.'... remote: Counting objects: 1994, done. remote: Compressing objects: 100% (150/150), done. From 82300990ec79f8ce6b2fca953d5548028a14aaea Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Thu, 10 Jun 2021 08:02:13 +0200 Subject: [PATCH 02/12] Fixes #5442: Use LDAP groups to find permissions When AUTH_LDAP_FIND_GROUP_PERMS is set to true the filter to find the users permissions is extended to search for all permissions assigned to groups in which the LDAP user is. --- netbox/netbox/authentication.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index 0eee2c13e..e696333ab 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -11,7 +11,7 @@ from users.models import ObjectPermission from utilities.permissions import permission_is_exempt, resolve_permission, resolve_permission_ct -class ObjectPermissionBackend(ModelBackend): +class ObjectPermissionMixin(): def get_all_permissions(self, user_obj, obj=None): if not user_obj.is_active or user_obj.is_anonymous: @@ -20,13 +20,16 @@ class ObjectPermissionBackend(ModelBackend): user_obj._object_perm_cache = self.get_object_permissions(user_obj) return user_obj._object_perm_cache + def get_permission_filter(self, user_obj): + return Q(users=user_obj) | Q(groups__user=user_obj) + def get_object_permissions(self, user_obj): """ Return all permissions granted to the user by an ObjectPermission. """ # Retrieve all assigned and enabled ObjectPermissions object_permissions = ObjectPermission.objects.filter( - Q(users=user_obj) | Q(groups__user=user_obj), + self.get_permission_filter(user_obj), enabled=True ).prefetch_related('object_types') @@ -86,6 +89,10 @@ class ObjectPermissionBackend(ModelBackend): return model.objects.filter(constraints, pk=obj.pk).exists() +class ObjectPermissionBackend(ObjectPermissionMixin, ModelBackend): + pass + + class RemoteUserBackend(_RemoteUserBackend): """ Custom implementation of Django's RemoteUserBackend which provides configuration hooks for basic customization. @@ -163,8 +170,15 @@ class LDAPBackend: "Required parameter AUTH_LDAP_SERVER_URI is missing from ldap_config.py." ) - # Create a new instance of django-auth-ldap's LDAPBackend - obj = LDAPBackend_() + # Create a new instance of django-auth-ldap's LDAPBackend with our own ObjectPermissions + class NBLDAPBackend(ObjectPermissionMixin, LDAPBackend_): + def get_permission_filter(self, user_obj): + permission_filter = Q(users=user_obj) | Q(groups__user=user_obj) + if self.settings.FIND_GROUP_PERMS: + permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) + return permission_filter + + obj = NBLDAPBackend() # Read LDAP configuration parameters from ldap_config.py instead of settings.py settings = LDAPSettings() From 76407401130734e6d224ebbcba19182560eba794 Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Thu, 10 Jun 2021 16:13:43 +0200 Subject: [PATCH 03/12] Use method from parent class Co-authored-by: Jeremy Stretch --- netbox/netbox/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index e696333ab..b20091d53 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -173,7 +173,7 @@ class LDAPBackend: # Create a new instance of django-auth-ldap's LDAPBackend with our own ObjectPermissions class NBLDAPBackend(ObjectPermissionMixin, LDAPBackend_): def get_permission_filter(self, user_obj): - permission_filter = Q(users=user_obj) | Q(groups__user=user_obj) + permission_filter = super().get_permission_filter(user_obj) if self.settings.FIND_GROUP_PERMS: permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) return permission_filter From 5bf4234ad3f2d0a02a1eda37d4a196d66970a7fb Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Tue, 15 Jun 2021 08:49:41 +0200 Subject: [PATCH 04/12] Fix error when running scripts This fixes the error Can't pickle local object 'LDAPBackend.__new__..NBLDAPBackend' --- netbox/netbox/authentication.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index b20091d53..03241e522 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -140,11 +140,25 @@ class RemoteUserBackend(_RemoteUserBackend): return False +# Create a new instance of django-auth-ldap's LDAPBackend with our own ObjectPermissions +try: + from django_auth_ldap.backend import LDAPBackend as LDAPBackend_ + + class NBLDAPBackend(ObjectPermissionMixin, LDAPBackend_): + def get_permission_filter(self, user_obj): + permission_filter = super().get_permission_filter(user_obj) + if self.settings.FIND_GROUP_PERMS: + permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) + return permission_filter +except ModuleNotFoundError: + pass + + class LDAPBackend: def __new__(cls, *args, **kwargs): try: - from django_auth_ldap.backend import LDAPBackend as LDAPBackend_, LDAPSettings + from django_auth_ldap.backend import LDAPSettings import ldap except ModuleNotFoundError as e: if getattr(e, 'name') == 'django_auth_ldap': @@ -170,14 +184,6 @@ class LDAPBackend: "Required parameter AUTH_LDAP_SERVER_URI is missing from ldap_config.py." ) - # Create a new instance of django-auth-ldap's LDAPBackend with our own ObjectPermissions - class NBLDAPBackend(ObjectPermissionMixin, LDAPBackend_): - def get_permission_filter(self, user_obj): - permission_filter = super().get_permission_filter(user_obj) - if self.settings.FIND_GROUP_PERMS: - permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) - return permission_filter - obj = NBLDAPBackend() # Read LDAP configuration parameters from ldap_config.py instead of settings.py From 4abfa6231c4a5006e4baa9b3306c9307c4c75092 Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Fri, 2 Jul 2021 07:55:13 +0200 Subject: [PATCH 05/12] Fixed bug for users authenticated with API token This prevents a crash when the current user has authenticated himself with an API token. In this case the user will not have the permissions given to his LDAP groups. --- netbox/netbox/authentication.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index 03241e522..2c843f076 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -147,7 +147,9 @@ try: class NBLDAPBackend(ObjectPermissionMixin, LDAPBackend_): def get_permission_filter(self, user_obj): permission_filter = super().get_permission_filter(user_obj) - if self.settings.FIND_GROUP_PERMS: + if (self.settings.FIND_GROUP_PERMS and + hasattr(user_obj, "ldap_user") and + hasattr(user_obj.ldap_user, "group_names")): permission_filter = permission_filter | Q(groups__name__in=user_obj.ldap_user.group_names) return permission_filter except ModuleNotFoundError: From a3d40e35212841bef7366953a39ff4c04e826bdd Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Mon, 5 Jul 2021 12:31:52 +0200 Subject: [PATCH 06/12] Load LDAP groups for API token authenticated users When users are authenticated with an API token not all permissions where assigned to the session because the LDAP group memberships where not available. Now the information is loaded from the directory if the user is found. If not the local group memberships are used. --- netbox/netbox/api/authentication.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index 1cb32c1e4..76bb0f983 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -25,6 +25,16 @@ class TokenAuthentication(authentication.TokenAuthentication): if not token.user.is_active: raise exceptions.AuthenticationFailed("User inactive") + # When LDAP authentication is active try to load user data from LDAP directory + if (settings.REMOTE_AUTH_ENABLED and + settings.REMOTE_AUTH_BACKEND == 'netbox.authentication.LDAPBackend'): + from netbox.authentication import LDAPBackend + ldap_backend = LDAPBackend() + user = ldap_backend.populate_user(token.user.username) + # If the user is found in the LDAP directory use it, if not fallback to the local user + if user: + return user, token + return token.user, token From b814123ede55e2052462648cb8e409f2c7df43fa Mon Sep 17 00:00:00 2001 From: Tobias Genannt Date: Fri, 9 Jul 2021 08:13:02 +0200 Subject: [PATCH 07/12] Only check REMOTE_AUTH_BACKEND in API token auth --- netbox/netbox/api/authentication.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index 76bb0f983..7f8bee318 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -26,8 +26,7 @@ class TokenAuthentication(authentication.TokenAuthentication): raise exceptions.AuthenticationFailed("User inactive") # When LDAP authentication is active try to load user data from LDAP directory - if (settings.REMOTE_AUTH_ENABLED and - settings.REMOTE_AUTH_BACKEND == 'netbox.authentication.LDAPBackend'): + if settings.REMOTE_AUTH_BACKEND == 'netbox.authentication.LDAPBackend': from netbox.authentication import LDAPBackend ldap_backend = LDAPBackend() user = ldap_backend.populate_user(token.user.username) From 0ed82af99a686ae27668ed2f5768d72675f475f7 Mon Sep 17 00:00:00 2001 From: Hans Erasmus Date: Fri, 9 Jul 2021 11:43:50 +0200 Subject: [PATCH 08/12] Update 3-netbox.md --- docs/installation/3-netbox.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 958cd4e46..2a493d835 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -74,7 +74,9 @@ Next, clone the **master** branch of the NetBox GitHub repository into the curre ```no-highlight $ sudo git clone -b master https://github.com/netbox-community/netbox.git . ``` + The screen below should be the result: + ``` Cloning into '.'... remote: Counting objects: 1994, done. From fd7d8cbf5604bd9dd1b88d13f1fbc000c0c88e47 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 12 Jul 2021 09:31:19 -0400 Subject: [PATCH 09/12] Changelog for #5442 --- docs/release-notes/version-2.11.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 1ff9a8483..3c4b071bf 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -1,5 +1,13 @@ # NetBox v2.11 +## v2.11.10 (FUTURE) + +### Bug Fixes + +* [#5442](https://github.com/netbox-community/netbox/issues/5442) - Fix assignment of permissions based on LDAP groups + +--- + ## v2.11.9 (2021-07-08) ### Bug Fixes From ab5a763d9347efcd4f4134f068b2f252fcfca565 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 14 Jul 2021 10:23:31 -0400 Subject: [PATCH 10/12] Updated issue staling timers --- CONTRIBUTING.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5707f4ad2..7a3b1f002 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -160,17 +160,20 @@ accumulating a large backlog of work. The core maintainers group has chosen to make use of GitHub's [Stale bot](https://github.com/apps/stale) to aid in issue management. -* Issues will be marked as stale after 45 days of no activity. -* Then after 15 more days of inactivity, the issue will be closed. +* Issues will be marked as stale after 60 days of no activity. +* If the stable label is not removed in the following 30 days, the issue will + be closed automatically. * Any issue bearing one of the following labels will be exempt from all Stale bot actions: * `status: accepted` * `status: blocked` * `status: needs milestone` -It is natural that some new issues get more attention than others. Stale bot -helps bring renewed attention to potentially valuable issues that may have been -overlooked. +It is natural that some new issues get more attention than others. The stale +bot helps bring renewed attention to potentially valuable issues that may have +been overlooked. **Do not** comment on an issue that has been marked stale in +an effort to circumvent the bot: Doing so will not remove the stale label. +(Stale labels can be removed only by maintainers.) ## Maintainer Guidance From dd0489c1c50b0709fc603e40261f144665338032 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 14 Jul 2021 10:43:18 -0400 Subject: [PATCH 11/12] Closes #6753: Add plugin removal instructions to the docs --- docs/plugins/index.md | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/plugins/index.md b/docs/plugins/index.md index 202e0a96b..c2d62330f 100644 --- a/docs/plugins/index.md +++ b/docs/plugins/index.md @@ -89,3 +89,58 @@ Restart the WSGI service to load the new plugin: ```no-highlight # sudo systemctl restart netbox ``` + +## Removing Plugins + +Follow these steps to completely remove a plugin. + +### Update Configuration + +Remove the plugin from the `PLUGINS` list in `configuration.py`. Also remove any relevant configuration parameters from `PLUGINS_CONFIG`. + +### Remove the Python Package + +Use `pip` to remove the installed plugin: + +```no-highlight +$ source /opt/netbox/venv/bin/activate +(venv) $ pip uninstall +``` + +### Restart WSGI Service + +Restart the WSGI service: + +```no-highlight +# sudo systemctl restart netbox +``` + +### Drop Database Tables + +!!! note + This step is necessary only for plugin which have created one or more database tables (generally through the introduction of new models). Check your plugin's documentation if unsure. + +Enter the PostgreSQL database shell to determine if the plugin has created any SQL tables. Substitute `pluginname` in the example below for the name of the plugin being removed. (You can also run the `\dt` command without a pattern to list _all_ tables.) + +```no-highlight +netbox=> \dt pluginname_* + List of relations + List of relations + Schema | Name | Type | Owner +--------+----------------+-------+-------- + public | pluginname_foo | table | netbox + public | pluginname_bar | table | netbox +(2 rows) +``` + +!!! warning + Exercise extreme caution when removing tables. Users are strongly encouraged to perform a backup of their database immediately before taking these actions. + +Drop each of the listed tables to remove it from the database: + +```no-highlight +netbox=> DROP TABLE pluginname_foo; +DROP TABLE +netbox=> DROP TABLE pluginname_bar; +DROP TABLE +``` From 61fe0e81cdd22c2fdc47d56b26e924763db8c4ec Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 20 Jul 2021 17:00:13 -0400 Subject: [PATCH 12/12] Fixes #6773: Add missing display field to rack unit serializer --- docs/release-notes/version-2.11.md | 1 + netbox/dcim/api/serializers.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 3c4b071bf..b8cd02ea7 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -5,6 +5,7 @@ ### Bug Fixes * [#5442](https://github.com/netbox-community/netbox/issues/5442) - Fix assignment of permissions based on LDAP groups +* [#6773](https://github.com/netbox-community/netbox/issues/6773) - Add missing `display` field to rack unit serializer --- diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index d9b36e9f2..c9d69fd00 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -210,6 +210,10 @@ class RackUnitSerializer(serializers.Serializer): face = ChoiceField(choices=DeviceFaceChoices, read_only=True) device = NestedDeviceSerializer(read_only=True) occupied = serializers.BooleanField(read_only=True) + display = serializers.SerializerMethodField(read_only=True) + + def get_display(self, obj): + return obj['name'] class RackReservationSerializer(PrimaryModelSerializer):