From 9b2534b6a2c9e080117ae2284eb3deffd13abbe2 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 911cbf2b183ab12f7fc1d72d5b6bc37fa4fa873a 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 f55cf993dda9860d387e819779e079374a43297b 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 fa94b80a13bb70a5dd56129aa8894d9c37938b15 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 c0ddb2092c141952efabd9fe2d1e7ffcd66da695 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 3b28ef7680a002742fc2c5223702360f62f82500 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 15bc6c74b205facef35a2801a7993c16ee26eed6 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 239a661a2a078c855afaab25f20a907d16631c3f 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 63b325b0f6c02497f210bd6f642191c5c3cec60f 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 ccc3eee6e7d754554500fcad8580c2636c606a94 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 904be9f9e953374543483806f42fb958c4115133 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 5d625867055d0216cca303269ac3246639c1b6a0 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):