Просмотр исходного кода

Implement custom auth backend and EXEMPT_VIEW_PERMISSIONS setting

Jeremy Stretch 6 лет назад
Родитель
Сommit
df0686a1bd

+ 24 - 0
docs/configuration/optional-settings.md

@@ -89,6 +89,30 @@ In order to send email, NetBox needs an email server configured. The following i
 
 ---
 
+## EXEMPT_VIEW_PERMISSIONS
+
+Default: Empty list
+
+A list of models to exempt from the enforcement of view permissions. Models listed here will be viewable by all users and by anonymous users.
+
+List models in the form `<app>.<model>`. For example:
+
+```
+EXEMPT_VIEW_PERMISSIONS = [
+    'dcim.site',
+    'dcim.region',
+    'ipam.prefix',
+]
+```
+
+To exempt _all_ models from view permission enforcement, set the following. (Note that `EXEMPT_VIEW_PERMISSIONS` must be an iterable.)
+
+```
+EXEMPT_VIEW_PERMISSIONS = ['*']
+```
+
+---
+
 # ENFORCE_GLOBAL_UNIQUE
 
 Default: False

+ 8 - 0
netbox/netbox/configuration.example.py

@@ -83,6 +83,14 @@ EMAIL = {
 # (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True.
 ENFORCE_GLOBAL_UNIQUE = False
 
+# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and
+# by anonymous users. List models in the form `<app>.<model>`. Add '*' to this list to exempt all models.
+EXEMPT_VIEW_PERMISSIONS = [
+    # 'dcim.site',
+    # 'dcim.region',
+    # 'ipam.prefix',
+]
+
 # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
 #   https://docs.djangoproject.com/en/1.11/topics/logging/
 LOGGING = {}

+ 7 - 2
netbox/netbox/settings.py

@@ -51,8 +51,9 @@ CORS_ORIGIN_WHITELIST = getattr(configuration, 'CORS_ORIGIN_WHITELIST', [])
 DATE_FORMAT = getattr(configuration, 'DATE_FORMAT', 'N j, Y')
 DATETIME_FORMAT = getattr(configuration, 'DATETIME_FORMAT', 'N j, Y g:i a')
 DEBUG = getattr(configuration, 'DEBUG', False)
-ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False)
 EMAIL = getattr(configuration, 'EMAIL', {})
+ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False)
+EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', [])
 LOGGING = getattr(configuration, 'LOGGING', {})
 LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False)
 LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None)
@@ -93,7 +94,7 @@ if LDAP_CONFIGURED:
         # Prepend LDAPBackend to the default ModelBackend
         AUTHENTICATION_BACKENDS = [
             'django_auth_ldap.backend.LDAPBackend',
-            'django.contrib.auth.backends.ModelBackend',
+            'utilities.auth_backends.ViewExemptModelBackend',
         ]
         # Optionally disable strict certificate checking
         if LDAP_IGNORE_CERT_ERRORS:
@@ -107,6 +108,10 @@ if LDAP_CONFIGURED:
             "LDAP authentication has been configured, but django-auth-ldap is not installed. You can remove "
             "netbox/ldap_config.py to disable LDAP."
         )
+else:
+    AUTHENTICATION_BACKENDS = [
+        'utilities.auth_backends.ViewExemptModelBackend',
+    ]
 
 # Database
 configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})

+ 28 - 0
netbox/utilities/auth_backends.py

@@ -0,0 +1,28 @@
+from django.conf import settings
+from django.contrib.auth.backends import ModelBackend
+
+
+class ViewExemptModelBackend(ModelBackend):
+    """
+    Custom implementation of Django's stock ModelBackend which allows for the exemption of arbitrary models from view
+    permission enforcement.
+    """
+    def has_perm(self, user_obj, perm, obj=None):
+
+        # If this is a view permission, check whether the model has been exempted from enforcement
+        try:
+            app, codename = perm.split('.')
+            action, model = codename.split('_')
+            if action == 'view':
+                if (
+                    # All models are exempt from view permission enforcement
+                    '*' in settings.EXEMPT_VIEW_PERMISSIONS
+                ) or (
+                    # This specific model is exempt from view permission enforcement
+                    '{}.{}'.format(app, model) in settings.EXEMPT_VIEW_PERMISSIONS
+                ):
+                    return True
+        except ValueError:
+            pass
+
+        return super().has_perm(user_obj, perm, obj)