Repository: nautobot/nautobot

Issue:
Catch CSRF Failure when DEBUG=False
### As ...

Patti - Platform Admin

### I want ...

the 403 CSRF failure to not render the default Django failure html when DEBUG is set to False

### So that ...

When errors occur in Nautobot a user remains in a view that has the same look and feel as nautobot and not a generic view without styling.

### I know this is done when...

- When form is submitted without CSRF token AND DEBUG is set to False a stylized view is returned with the error.
- When form is submitted and fails CSRF validation AND DEBUG is set to False a stylized view is returned with the error.
- When form is submitted without CSRF token AND DEBUG is set to True the default Django view is returned.
- When form is submitted and fails CSRF validation AND DEBUG is set to True the default Django view is returned.

### Optional - Feature groups this request pertains to.

- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [ ] Misc (including Data Sources)
- [ ] Organization
- [ ] Plugins (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [X] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)

### Database Changes

None

### External Dependencies

None


Discussion:

Resolving patch:
diff --git a/nautobot/core/settings.py b/nautobot/core/settings.py
--- a/nautobot/core/settings.py
+++ b/nautobot/core/settings.py
@@ -273,6 +273,7 @@
 # Default overrides
 ALLOWED_HOSTS = []
 CSRF_TRUSTED_ORIGINS = []
+CSRF_FAILURE_VIEW = "nautobot.core.views.csrf_failure"
 DATETIME_FORMAT = "N j, Y g:i a"
 INTERNAL_IPS = ("127.0.0.1", "::1")
 FORCE_SCRIPT_NAME = None
diff --git a/nautobot/core/views/__init__.py b/nautobot/core/views/__init__.py
--- a/nautobot/core/views/__init__.py
+++ b/nautobot/core/views/__init__.py
@@ -4,13 +4,14 @@
 
 from django.conf import settings
 from django.contrib.auth.mixins import AccessMixin
-from django.http import HttpResponseServerError, JsonResponse
+from django.http import HttpResponseServerError, JsonResponse, HttpResponseForbidden
 from django.shortcuts import render
 from django.template import loader, RequestContext, Template
 from django.template.exceptions import TemplateDoesNotExist
 from django.urls import reverse
 from django.views.decorators.csrf import requires_csrf_token
 from django.views.defaults import ERROR_500_TEMPLATE_NAME, page_not_found
+from django.views.csrf import csrf_failure as _csrf_failure
 from django.views.generic import TemplateView, View
 from packaging import version
 from graphene_django.views import GraphQLView
@@ -196,6 +197,20 @@ def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
     )
 
 
+def csrf_failure(request, reason="", template_name="403_csrf_failure.html"):
+    """Custom 403 CSRF failure handler to account for additional context.
+
+    If Nautobot is set to DEBUG the default view for csrf_failure.
+    `403_csrf_failure.html` template name is used over `403_csrf.html` to account for
+    additional context that is required to render the inherited templates.
+    """
+    if settings.DEBUG:
+        return _csrf_failure(request, reason=reason)
+    t = loader.get_template(template_name)
+    context = {"settings": settings, "reason": reason}
+    return HttpResponseForbidden(t.render(context), content_type="text/html")
+
+
 class CustomGraphQLView(GraphQLView):
     def render_graphiql(self, request, **data):
         query_slug = request.GET.get("slug")


Test patch: