Issue #3906
closedbrowsable API inserts a csrf token field into all form submissions
Description
Pulp's REST API validates that only acceptable fields are submitted with each request. The list of fields does not include the csrf token. As a result of this validation, the browsable API forms produce responses that look like this:
HTTP 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"csrfmiddlewaretoken": [
"Unexpected field"
]
}
We need to investigate how to configure DRF to stop including this field with each form. Otherwise a fix from comment 3 would be appropriate.
Notes¶
To easily reproduce, navigate your browser to e.g http://localhost:8000/pulp/api/v3/repositories/ and create a repository by filling-in the create repository form.
This happens when session authentication is used such as with a browser; non-session authentication won't trigger the CSRF protection.
Unfortunately it seems the session-authentication is somehow mandatory or at least I wasn't able to just switch it off:
pulp: django.request:ERROR: Internal Server Error: /pulp/api/v3/repositories/
Traceback (most recent call last):
File "/home/vagrant/.virtualenvs/pulp/lib64/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/vagrant/.virtualenvs/pulp/lib64/python3.6/site-packages/django/utils/deprecation.py", line 90, in __call__
response = self.process_request(request)
File "/home/vagrant/.virtualenvs/pulp/lib64/python3.6/site-packages/django/contrib/auth/middleware.py", line 23, in process_request
) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
AssertionError: The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.sessions.middleware.SessionMiddleware' before 'django.contrib.auth.middleware.AuthenticationMiddleware'.
[13/Aug/2018 13:15:14] "GET /pulp/api/v3/repositories/ HTTP/1.1" 500 69693
Discussion¶
The session authentication is configured for particular Django application in app/settings.py
:
MIDDLEWARE = [
...
django.middleware.csrf.CsrfViewMiddleware,
django.contrib.auth.middleware.AuthenticationMiddleware,
]
...
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': [
rest_framework.authentication.SessionAuthentication,
rest_framework.authentication.BasicAuthentication,
]
}
DRF uses a custom authentication class SessionAuthentication
that in turn utilizes the Django middleware CsrfViewMiddleware
class thru the CSRFCheck
class, so the CsrfViewMiddleware:process_view
gets eventually triggered. The request_csrf_token
is then extracted from the request.POST.get('csrfmiddlewaretoken')
form field, which is unset neither in the Django nor in the DRF middleware classes and the csrfmiddlewaretoken
form field gets eventually propagated into a Pulp create object view.
Good news is we should be fine to just ignore it; "greping" over Github, this particular csrfmiddlewaretoken
string shows quite often in the code so often in fact that I can't confirm some of it being DRF/Django workarounds.
Related issues
Serializer ignore the csrfmiddlewaretoken field
The CSRF protection middleware kicks-in when a browser is used to access Pulp API, after the user having successfully logged into Pulp, i.e whenever a Session-based authentication is used by the DRF/Django The middleware uses a custom (and invisible) form field:
csrfmiddlewaretoken
that the page in the browser populates from a CSRF cookie previously generated by Django whenever issuing a POST/PATCH/DELETE... request to prevent the cross-site-request-forgery. The whole mechanism is nicely described on wikipedia.This
csrfmiddlewaretoken
field unfortunately isn't stripped from the POSTed data by either DRF or Django, and causes our serializers to fail validate form data because of it being an unknown field to our models.This patch just makes our validation ignore the unknow
csrfmiddlewaretoken
field.Fixes: #3906 https://pulp.plan.io/issues/3906