Explorar o código

Fixes #12061: Improve handling of insufficient permissions for widget content

jeremystretch %!s(int64=2) %!d(string=hai) anos
pai
achega
424b336536

+ 16 - 5
netbox/extras/dashboard/widgets.py

@@ -11,6 +11,7 @@ from django.urls import NoReverseMatch, reverse
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
 from utilities.forms import BootstrapMixin
 from utilities.forms import BootstrapMixin
+from utilities.permissions import get_permission_for_model
 from utilities.templatetags.builtins.filters import render_markdown
 from utilities.templatetags.builtins.filters import render_markdown
 from utilities.utils import content_type_identifier, content_type_name, get_viewname
 from utilities.utils import content_type_identifier, content_type_name, get_viewname
 from .utils import register_widget
 from .utils import register_widget
@@ -107,8 +108,12 @@ class ObjectCountsWidget(DashboardWidget):
         for content_type_id in self.config['models']:
         for content_type_id in self.config['models']:
             app_label, model_name = content_type_id.split('.')
             app_label, model_name = content_type_id.split('.')
             model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
             model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
-            object_count = model.objects.restrict(request.user, 'view').count
-            counts.append((model, object_count))
+            permission = get_permission_for_model(model, 'view')
+            if request.user.has_perm(permission):
+                object_count = model.objects.restrict(request.user, 'view').count
+                counts.append((model, object_count))
+            else:
+                counts.append((model, None))
 
 
         return render_to_string(self.template_name, {
         return render_to_string(self.template_name, {
             'counts': counts,
             'counts': counts,
@@ -136,15 +141,21 @@ class ObjectListWidget(DashboardWidget):
 
 
     def render(self, request):
     def render(self, request):
         app_label, model_name = self.config['model'].split('.')
         app_label, model_name = self.config['model'].split('.')
-        content_type = ContentType.objects.get_by_natural_key(app_label, model_name)
-        viewname = get_viewname(content_type.model_class(), action='list')
+        model = ContentType.objects.get_by_natural_key(app_label, model_name).model_class()
+        viewname = get_viewname(model, action='list')
+
+        # Evaluate user's permission. Note that this controls only whether the HTMX element is
+        # embedded on the page: The view itself will also evaluate permissions separately.
+        permission = get_permission_for_model(model, 'view')
+        has_permission = request.user.has_perm(permission)
+
         try:
         try:
             htmx_url = reverse(viewname)
             htmx_url = reverse(viewname)
         except NoReverseMatch:
         except NoReverseMatch:
             htmx_url = None
             htmx_url = None
-
         return render_to_string(self.template_name, {
         return render_to_string(self.template_name, {
             'viewname': viewname,
             'viewname': viewname,
+            'has_permission': has_permission,
             'htmx_url': htmx_url,
             'htmx_url': htmx_url,
             'page_size': self.config.get('page_size'),
             'page_size': self.config.get('page_size'),
         })
         })

+ 11 - 4
netbox/templates/extras/dashboard/widgets/objectcounts.html

@@ -3,12 +3,19 @@
 {% if counts %}
 {% if counts %}
   <div class="list-group list-group-flush">
   <div class="list-group list-group-flush">
     {% for model, count in counts %}
     {% for model, count in counts %}
-      <a href="{% url model|viewname:"list" %}" class="list-group-item list-group-item-action">
-        <div class="d-flex w-100 justify-content-between align-items-center">
+      {% if count != None %}
+        <a href="{% url model|viewname:"list" %}" class="list-group-item list-group-item-action">
+          <div class="d-flex w-100 justify-content-between align-items-center">
+            {{ model|meta:"verbose_name_plural"|bettertitle }}
+            <h6 class="mb-1">{{ count }}</h6>
+          </div>
+        </a>
+      {% else %}
+        <div class="list-group-item list-group-item-action d-flex w-100 justify-content-between align-items-center">
           {{ model|meta:"verbose_name_plural"|bettertitle }}
           {{ model|meta:"verbose_name_plural"|bettertitle }}
-          <h6 class="mb-1">{{ count }}</h6>
+          <h6 class="mb-1" title="No permission"><i class="mdi mdi-lock-outline"></i></h6>
         </div>
         </div>
-      </a>
+      {% endif %}
     {% endfor %}
     {% endfor %}
   </div>
   </div>
 {% endif %}
 {% endif %}

+ 5 - 1
netbox/templates/extras/dashboard/widgets/objectlist.html

@@ -1,5 +1,9 @@
-{% if htmx_url %}
+{% if htmx_url and has_permission %}
   <div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
   <div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
+{% elif htmx_url %}
+  <div class="text-muted text-center">
+    <i class="mdi mdi-lock-outline"></i> No permission to view this content.
+  </div>
 {% else %}
 {% else %}
   <div class="text-danger text-center">
   <div class="text-danger text-center">
     <i class="mdi mdi-alert"></i> Unable to load content. Invalid view name: <span class="font-monospace">{{ viewname }}</span>
     <i class="mdi mdi-alert"></i> Unable to load content. Invalid view name: <span class="font-monospace">{{ viewname }}</span>