Closes #16580: Remove AUTH_EXEMPT_PATHS (#16662)

* Closes #16580: Remove AUTH_EXEMPT_PATHS

* Misc cleanup
This commit is contained in:
Jeremy Stretch 2024-06-26 12:05:38 -04:00 committed by GitHub
parent 52546608f6
commit c22463f4aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 27 additions and 32 deletions

View File

@ -1200,7 +1200,7 @@ class ScriptResultView(TableMixin, generic.ObjectView):
# Markdown # Markdown
# #
class RenderMarkdownView(View): class RenderMarkdownView(LoginRequiredMixin, View):
def post(self, request): def post(self, request):
form = forms.RenderMarkdownForm(request.POST) form = forms.RenderMarkdownForm(request.POST)

View File

@ -1,6 +1,5 @@
import logging import logging
import uuid import uuid
from urllib import parse
from django.conf import settings from django.conf import settings
from django.contrib import auth, messages from django.contrib import auth, messages
@ -33,16 +32,6 @@ class CoreMiddleware:
# Assign a random unique ID to the request. This will be used for change logging. # Assign a random unique ID to the request. This will be used for change logging.
request.id = uuid.uuid4() request.id = uuid.uuid4()
# Enforce the LOGIN_REQUIRED config parameter. If true, redirect all non-exempt unauthenticated requests
# to the login page.
if (
settings.LOGIN_REQUIRED and
not request.user.is_authenticated and
not request.path_info.startswith(settings.AUTH_EXEMPT_PATHS)
):
login_url = f'{settings.LOGIN_URL}?next={parse.quote(request.get_full_path_info())}'
return HttpResponseRedirect(login_url)
# Enable the event_tracking context manager and process the request. # Enable the event_tracking context manager and process the request.
with event_tracking(request): with event_tracking(request):
response = self.get_response(request) response = self.get_response(request)

View File

@ -502,15 +502,6 @@ EXEMPT_EXCLUDE_MODELS = (
('users', 'user'), ('users', 'user'),
) )
# All URLs starting with a string listed here are exempt from login enforcement
AUTH_EXEMPT_PATHS = (
f'/{BASE_PATH}api/',
f'/{BASE_PATH}graphql/',
f'/{BASE_PATH}login/',
f'/{BASE_PATH}oauth/',
f'/{BASE_PATH}metrics',
)
# All URLs starting with a string listed here are exempt from maintenance mode enforcement # All URLs starting with a string listed here are exempt from maintenance mode enforcement
MAINTENANCE_EXEMPT_PATHS = ( MAINTENANCE_EXEMPT_PATHS = (
f'/{BASE_PATH}admin/', f'/{BASE_PATH}admin/',

View File

@ -1,3 +1,4 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction
@ -12,7 +13,7 @@ from extras.forms import JournalEntryForm
from extras.models import JournalEntry from extras.models import JournalEntry
from extras.tables import JournalEntryTable from extras.tables import JournalEntryTable
from utilities.permissions import get_permission_for_model from utilities.permissions import get_permission_for_model
from utilities.views import GetReturnURLMixin, ViewTab from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab
from .base import BaseMultiObjectView from .base import BaseMultiObjectView
__all__ = ( __all__ = (
@ -24,7 +25,7 @@ __all__ = (
) )
class ObjectChangeLogView(View): class ObjectChangeLogView(ConditionalLoginRequiredMixin, View):
""" """
Present a history of changes made to a particular object. The model class must be passed as a keyword argument Present a history of changes made to a particular object. The model class must be passed as a keyword argument
when referencing this view in a URL path. For example: when referencing this view in a URL path. For example:
@ -77,7 +78,7 @@ class ObjectChangeLogView(View):
}) })
class ObjectJournalView(View): class ObjectJournalView(ConditionalLoginRequiredMixin, View):
""" """
Show all journal entries for an object. The model class must be passed as a keyword argument when referencing this Show all journal entries for an object. The model class must be passed as a keyword argument when referencing this
view in a URL path. For example: view in a URL path. For example:
@ -138,7 +139,7 @@ class ObjectJournalView(View):
}) })
class ObjectJobsView(View): class ObjectJobsView(ConditionalLoginRequiredMixin, View):
""" """
Render a list of all Job assigned to an object. For example: Render a list of all Job assigned to an object. For example:
@ -191,7 +192,7 @@ class ObjectJobsView(View):
}) })
class ObjectSyncDataView(View): class ObjectSyncDataView(LoginRequiredMixin, View):
def post(self, request, model, **kwargs): def post(self, request, model, **kwargs):
""" """

View File

@ -1,3 +1,4 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404 from django.http import Http404
@ -6,7 +7,7 @@ from django.utils.module_loading import import_string
from django.views.generic import View from django.views.generic import View
class ObjectSelectorView(View): class ObjectSelectorView(LoginRequiredMixin, View):
template_name = 'htmx/object_selector.html' template_name = 'htmx/object_selector.html'
def get(self, request): def get(self, request):

View File

@ -19,6 +19,7 @@ from netbox.search.backends import search_backend
from netbox.tables import SearchTable from netbox.tables import SearchTable
from utilities.htmx import htmx_partial from utilities.htmx import htmx_partial
from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.paginator import EnhancedPaginator, get_paginate_count
from utilities.views import ConditionalLoginRequiredMixin
__all__ = ( __all__ = (
'HomeView', 'HomeView',
@ -28,7 +29,7 @@ __all__ = (
Link = namedtuple('Link', ('label', 'viewname', 'permission', 'count')) Link = namedtuple('Link', ('label', 'viewname', 'permission', 'count'))
class HomeView(View): class HomeView(ConditionalLoginRequiredMixin, View):
template_name = 'home.html' template_name = 'home.html'
def get(self, request): def get(self, request):
@ -62,7 +63,7 @@ class HomeView(View):
}) })
class SearchView(View): class SearchView(ConditionalLoginRequiredMixin, View):
def get(self, request): def get(self, request):
results = [] results = []

View File

@ -1,5 +1,6 @@
from typing import Iterable from typing import Iterable
from django.conf import settings
from django.contrib.auth.mixins import AccessMixin from django.contrib.auth.mixins import AccessMixin
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse from django.urls import reverse
@ -13,6 +14,7 @@ from utilities.relations import get_related_models
from .permissions import resolve_permission from .permissions import resolve_permission
__all__ = ( __all__ = (
'ConditionalLoginRequiredMixin',
'ContentTypePermissionRequiredMixin', 'ContentTypePermissionRequiredMixin',
'GetRelatedModelsMixin', 'GetRelatedModelsMixin',
'GetReturnURLMixin', 'GetReturnURLMixin',
@ -27,10 +29,20 @@ __all__ = (
# View Mixins # View Mixins
# #
class ContentTypePermissionRequiredMixin(AccessMixin): class ConditionalLoginRequiredMixin(AccessMixin):
"""
Similar to Django's LoginRequiredMixin, but enforces authentication only if LOGIN_REQUIRED is True.
"""
def dispatch(self, request, *args, **kwargs):
if settings.LOGIN_REQUIRED and not request.user.is_authenticated:
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
class ContentTypePermissionRequiredMixin(ConditionalLoginRequiredMixin):
""" """
Similar to Django's built-in PermissionRequiredMixin, but extended to check model-level permission assignments. Similar to Django's built-in PermissionRequiredMixin, but extended to check model-level permission assignments.
This is related to ObjectPermissionRequiredMixin, except that is does not enforce object-level permissions, This is related to ObjectPermissionRequiredMixin, except that it does not enforce object-level permissions,
and fits within NetBox's custom permission enforcement system. and fits within NetBox's custom permission enforcement system.
additional_permissions: An optional iterable of statically declared permissions to evaluate in addition to those additional_permissions: An optional iterable of statically declared permissions to evaluate in addition to those
@ -63,7 +75,7 @@ class ContentTypePermissionRequiredMixin(AccessMixin):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class ObjectPermissionRequiredMixin(AccessMixin): class ObjectPermissionRequiredMixin(ConditionalLoginRequiredMixin):
""" """
Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level
permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered