core: return the intended status code from error views for all request methods - #24902
Conversation
…t methods The views wired up as django's handler400/403/404/500 subclassed TemplateView directly. TemplateView only implements `get`, so its `dispatch` answers a failing POST/PUT/PATCH/DELETE with 405 Method Not Allowed and an `Allow: GET, HEAD, OPTIONS` header, discarding the status code the handler stands for. Any non-GET request that reached an error handler -- on any endpoint -- was reported as a 405 rather than the actual 400/403/404/500. Add a shared ErrorView base that renders the page for every method, and widen the dramatiq result handling in the outgoing sync mixin from ResultFailure to ResultError so a queued-but-not-yet-reported task returns the task log instead of escaping as an unhandled 500. closes goauthentik#24230
✅ Deploy Preview for authentik-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Signed-off-by: Jens L. <jens@beryju.org>
✅ Deploy Preview for authentik-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for authentik-integrations ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #24902 +/- ##
==========================================
- Coverage 91.38% 91.37% -0.01%
==========================================
Files 1137 1147 +10
Lines 71626 71858 +232
Branches 3875 3875
==========================================
+ Hits 65452 65663 +211
- Misses 6139 6160 +21
Partials 35 35
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
|
🍒 Cherry-pick to |
|
🍒 Cherry-pick to |
|
🍒 Cherry-pick to |
…t methods (cherry-pick #24902 to version-2026.8) (#24958) core: return the intended status code from error views for all request methods (#24902) * core: return the intended status code from error views for all request methods The views wired up as django's handler400/403/404/500 subclassed TemplateView directly. TemplateView only implements `get`, so its `dispatch` answers a failing POST/PUT/PATCH/DELETE with 405 Method Not Allowed and an `Allow: GET, HEAD, OPTIONS` header, discarding the status code the handler stands for. Any non-GET request that reached an error handler -- on any endpoint -- was reported as a 405 rather than the actual 400/403/404/500. Add a shared ErrorView base that renders the page for every method, and widen the dramatiq result handling in the outgoing sync mixin from ResultFailure to ResultError so a queued-but-not-yet-reported task returns the task log instead of escaping as an unhandled 500. closes #24230 * Apply suggestion from @rissson --------- Signed-off-by: Jens L. <jens@beryju.org> Co-authored-by: Souptik Chakraborty <62941615+Souptik96@users.noreply.github.com> Co-authored-by: Jens L. <jens@beryju.org> Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Details
What does this PR change?
The four views wired up as django's
handler400/403/404/500inauthentik/root/urls.pysubclassed
TemplateViewdirectly.TemplateViewonly implementsget, so itsdispatch()answers a failingPOST/PUT/PATCH/DELETEwith405 Method Not Allowedand anAllow: GET, HEAD, OPTIONSheader, discarding the status code thehandler stands for.
ErrorViewbase inauthentik/core/views/error.pythat renders theerror page for every request method, so
BadRequestView/ForbiddenView/NotFoundView/ServerErrorViewreturn 400/403/404/500 respectively regardless ofmethod. This also removes the duplicated
template_nameand theServerErrorView.dispatch# pragma: no coverwrapper it made redundant.OutgoingSyncProviderStatusMixin.sync_object(
authentik/lib/sync/outgoing/api.py) fromResultFailuretoResultError, soResultTimeout/ResultMissing— a task that is queued but has not reported yet —returns the task's messages instead of escaping as an unhandled 500.
authentik/core/tests/test_error_views.pycovering both the handler statuscodes per method and the end-to-end unresolvable-API-path case.
Why is this change needed?
Reported in #24230:
POST /api/v3/providers/scim/{id}/sync/object/with an invalid IDreturns
405 Method Not Allowedinstead of a descriptive error. The endpoint is notactually at fault — it is the error handlers.
Two things combine:
(?P<pk>[^/.]+), so an idcontaining a dot never resolves and django raises
Http404at the resolver, beforeany view runs.
handler404then answers thePOSTwith 405 rather than 404.get_result()raisesResultTimeout/ResultMissing, which was not caught. That unhandled exceptionreaches
handler500, which likewise answers thePOSTwith 405 instead of 500.The defect is repo-wide, not SCIM-specific: any non-GET request that reaches an error
handler on any endpoint was reported as 405.
schema.ymldeclares only 200/400/403 forthis operation, so a 405 is not a documented outcome and the web UI's
SyncObjectForm.tshas no way to surface it usefully.How was this tested?
make allcould not be run in my environment, and I want to be upfront about that:uv sync --frozenfails locally while buildingdumb-init('Compiler' object has no attribute 'linker_exe') and thenpsycopg-c(couldn't run 'pg_config' --includedir), and I have no docker/postgres available. So the django test suite andthe lint matrix could not execute against the real project. Please rely on CI for
make all.What I did instead, to avoid submitting an unverified guess:
error.pyby path anddrives the handlers through
RequestFactory, plus a DRFAPIClientreproducing therouter-level 404 and the unhandled-exception paths.
GETbut405forPOST/PUT/PATCH/DELETE; a pk containing a dot and anunhandled exception both surface as 405.
Allowheader is gone.error.pyreverted, the testfails with 16 assertion failures, the first being
AssertionError: 405 != 500.ruff checkandblack --checkpass on the three touched files.No serializers or viewsets changed shape, so no
make genoutput changes are expected.Linked issues
closes #24230
Checklist
make all) — see "How was thistested?"; blocked locally by the
uv syncbuild failures described above.make docs) — n/a, no docs touchedDisclosure: yes, I used agentic AI assistance while preparing this change. The
diagnosis, the repros, and the negative control described above are real and were run;
please review accordingly, and let me know if you would rather I close this.