volingas
volingas

Reputation: 1173

Django test client does not provide the right authentication headers

When sending a request to the development server, I can include a header as follows:

Authorization: Token efc7fa291f4e320ff4a31cf9a11d6de3a366937cd1ec24e0a7ab68dafa38430f\r\n

Internally Django sees an HTTP_AUTHORIZATION header, which I am not sure where is generated.

But when using the Django test client for unit testing:

from django.test import Client

c = Client()
response = c.get('/api/auth/user/', **{'Authorization': 'Token ' + token})

Django can not authorize the request.

If instead I do the following:

response = c.get('/api/auth/user/', **{'HTTP_AUTHORIZATION': 'Token ' + token})

It works.

I would like to understand what is going on.

Who is responsible of performing the mapping Authorization -> HTTP_AUTHORIZATION?

Relevant for this question: I am using Django 2.1.5, djangorestframework = "==3.9.0" and djangorestframework = "==3.9.0"

Upvotes: 8

Views: 962

Answers (1)

dirkgroten
dirkgroten

Reputation: 20702

This is what the Django documentation says:

The headers sent via **extra should follow CGI specification. For example, emulating a different “Host” header as sent in the HTTP request from the browser to the server should be passed as HTTP_HOST.

And here's the relevant CGI quote:

HTTP_* :

These variables are specific to requests made with HTTP. Interpretation of these variables may depend on the value of SERVER_PROTOCOL.

Environment variables with names beginning with "HTTP_" contain header data read from the client, if the protocol used was HTTP. The HTTP header name is converted to upper case, has all occurrences of "-" replaced with "" and has "HTTP" prepended to give the environment variable name. The header data may be presented as sent by the client, or may be rewritten in ways which do not change its semantics. If multiple headers with the same field-name are received then they must be rewritten as a single header having the same semantics. Similarly, a header that is received on more than one line must be merged onto a single line. The server must, if necessary, change the representation of the data (for example, the character set) to be appropriate for a CGI environment variable.

This is what Django sees, since all your requests are processed by a CGI-compatible app server (WSGI actually, gunicorn and uwsgi for example). So basically the test client wants a CGI request, which means your have to convert the HTTP headers according to the rules above.

Upvotes: 4

Related Questions