Django csrf token - django

views.py
from django.core.context_processors import csrf
context.update(csrf(request))
{'csrf_token': <django.utils.functional.__proxy__ object at 0xae0f4ec>}
I am trying to add csrf token to my forms.i m generating csrf token in the views like above.But csrf_token value gives some proxy object like the one shown above instead of string.I m using django 1.3.Thanks in advance for any sort of help.

The csrf method is lazy, it returns a Promise/Proxy. Once this object is called in the template, the template engine will unicode this object which triggers the real method.
Try this:
print unicode(csrf(request)['csrf_token'])

Related

Django DRF - Manually validate CSRF token

I read in the docs that DRF only validates CSRF tokens on authenticated requests and login views should explicitely check the CSRF token.
Problem is, how does one manually check the CSRF token?
In my settings.py:
MIDDLEWARE = [
...
"django.middleware.csrf.CsrfViewMiddleware",
...
]
Here's my view:
from rest_framework.decorators import api_view
from django.http import JsonResponse
from django.views.decorators.csrf import get_token
# I have to manually generate the csrf token and put it in the response body, because I use react-native and that can't read the token from the 'Set-Cookie' header
#api_view(["GET"])
def user_info(request):
return JsonResponse({"csrf_token": get_token(request)})
#api_view(["POST"])
def login(request):
return JsonResponse({"foo": "bar"})
When I make a POST request in the frontend and I don't provide the CSRF token, it should fail, but I actually receive the {"foo": "bar"} JSON.
I tried the #csrf_protect and #requires_csrf_token decorators, but the request is still not failing.
I also tried this, but that errors on required positional argument: 'get_response
CsrfViewMiddleware().process_view(request, None, (), {})
If I pass a function to get_response, that function is never called:
def test_get_response(req):
breakpoint()
CsrfViewMiddleware(get_response=test_get_response).process_request(request)
I checked that the CSRF token is not passed in the headers, not the cookies, and I tried different browsers and incognito mode.
How do I get my api requests to fail if they don't include a valid CSRF token?
You're having error in this importing from django.views.decorators.csrf import get_token . you should import get_token from django.middleware.csrf .
according to django documentation and it return the CSRF token required for a POST form.
Okay... a few rabbit holes later, I found some kind of solution.
Django uses Double Submit Cookie for CSRF validation. This means:
Frontend requests CSRF token from Django
Django generates token, sends it to FE in Set-Cookie header
FE puts csrf in cookie, which cannot be altered by a potential attacker
FE puts the same token in POST form and sends it to Django
Django checks if token in POST form and cookie are the same
Problem is, React Native doesn't support cookies, so it has to send the CSRF token some other way. Problem with that is there is not way to do that securely.
I solved it by writing custom middleware for django:
FE requests CSRF token from Django
Django generates token, sends it to FE, AND stores hashed version in db
FE puts it in POST form and sends it to Django
Django hashes the token, checks if hash is in db
Upon successful validation, Django removes token from db
A CRON job removes any unused tokens after 24 hours
Bit cumbersome, but I only have to validate this way on web requests.

DRF - extend obtain auth token

I have Django Rest Framework with token auth. I have a following url url(r'^api/auth/', views.obtain_auth_token), which returns me token.
What I need to do is perform some db logic, when user performs authorization which is getting the token. I need to query db and do some stuff there.
It seems to me that I have somehow to override default behaviour and add some custom logic to obtain_auth_token.
How can I do that ?
ObtainAuthToken from Rest Framework gets or creates a token for an specific user and then sends it in the Response, all of these behaviour is done in the post method.
The documentation says:
If you need a customized version of the obtain_auth_token view, you can do so by overriding the ObtainAuthToken view class, and using that in your url conf instead.
So you can override the post method, or even create your own APIView to create the Token and add the behaviour you want. In order to do that, change your url:
url(r'^api/auth/', views.custom_obtain_token)
And in views.py:
class CustomObtainToken(APIView):
...
def post(self, request):
<your logic>
<get token n your own way or using DRF way>
return Response({'token': token})
custom_obtain_token = CustomObtainToken.as_view()

how to disable csrf in testing django?

I have a problem testing views with csrf tokens.
This code
class ViewTests(TestCase):
def test_bets_view(self):
login_page = self.client.get('/users/login/')
print(login_page.content)
returns HTML with CSRF hidden input.
And this thing, which I need to compare to the former HTML,
expected_html = render_to_response('login.html',
dictionary={'form': LoginForm()})
doesn't have hidden CSRF input. So the assertion fails.
Ho do I disable CSRF rendering in test client?
You can override your middleware settings in your unit test like this:
from django.test import override_settings
testing_middleware = [ ... anything but csrf middleware goes here ]
class TestWhatever(TestCase)
#override_settings(MIDDLEWARE=testing_middleware)
def testSomething():
# no csrf error will occur
self.client.post('/', data={ ... })
First you get the page in your tests and extract the csrf token from it:
page = self.client.get("/users/login")
token = page.context.get("csrf_token")
Then you use the same token to render the template and compare:
expected_html = TemplateResponse(
page.wsgi_request,
"login.html",
context={"form": LoginForm(), "csrf_token": token}).render()
assert expected_html.content == page.content
You should never compare the complete HTML content. Just check the functionalities. In case you need disabling the csrf at any cost, following logic should help I guess.
In your views.py file, add the following package
from django.views.decorators.csrf import csrf_exempt
Then just before the function definintion, in which you are performing your checks, add this snippet:
#csrf_exempt
This will disable the default verification of csrf. Even if your incoming request has a hidden csrf token, your server function will completely ignore it. This should do the trick of disabling the csrf.

How to convert a Django HttpResponse to a Django render call

I have the following code
def ajax_login_request(request):
try:
request.POST[u'login']
dictionary = request.POST
except:
dictionary = request.GET
user = authenticate(username = dictionary[u'login'], password = dictionary[u'password'])
if user and user.is_active:
login(request, user)
result = True
else:
result = False
response = HttpResponse(json.dumps(result), mimetype = u'application/json')
return response
which is being called via ajax. I'm a noob and this is from an example in a book. Unfortunately the version of Django I'm using throws a CSRF error on this. I've done the other CSRF bits, but I don't know how to change the HttpResponse bit to a render call. I do not want to use CSRF_exempt, because I have no idea when that is appropriate. Can someone please provide me the equivalent render call for the HttpResponse above.
Thanks
To make your original code work, you need to get a RequestContext object and pass it along with your response, something like this:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ajax_login_request(request):
# ...
# This bit of code adds the CSRF bits to your request.
c = RequestContext(request,{'result':json.dumps(result)})
t = Template("{{result}}") # A dummy template
response = HttpResponse(t.render(c), mimetype = u'application/json')
return response
Do read up on the CSRF documentation as you might run into strange errors if you don't understand all the ways CSRF is "wired" in your app. The page also has a javascript snippet to make sure CSRF cookies are sent with your ajax requests if you are sending them without a form.
You can also use the render_to_response() shortcut, but you would need to have an actual template to load (in your case, you don't need a template, hence the "dummy" template in my example).
Ok, I'm going to re-draft this answer so you understand where I'm coming from. The CSRF middleware works like this:
You make request -------> request hits csrf --(invalid/no token)--> render 403
middleware
|
(valid token)
|
\ /
Call view
|
\ /
middleware sets
csrf cookie
|
\ /
Response appears
In other words, if you are seeing a 403 csrf page, your view was never called. You can confirm this by sticking a spurious print statement in the view and watching the output from runserver when you make your request.
To solve this, you either need to disable csrf (not good) or use one of the ajax methods available to you. If the required token is passed in your view will actually be executed.
The reason your view is not called is to prevent the action from the forged site from actually ever taking place - for example, if you denied the template at response time the user would already be logged in. The same behaviour occurs with the function decorators.
As for the middleware setting the cookie, that does not alter or depend on the render function at all - this sets the HTTP header Cookie: ... in the response. All responses in Django are HttpResponse objects until it finally converts them to output; render functions are helpers, but that's not what's causing your problem here.
Edit I'll convert what you've got to a render call. You could do this:
return render_to_response(`ajax_templates/login_response.html`,
{'loginresponse': json.dumps(result)})
Where ajax_templates/login_response.html is just:
{% loginresponse %}
That's it. HttpResponse has a main default argument which is the string to return (literally, the html of the web page); that's what you're doing initially. render_to_response and render are shortcuts to this which do this:
render_to_response called ----> open template asked for --> substitute arguments
|
\ /
django instructs web server <--- return this from view <-- create HttpResponse
to send to client object

SWFUpload with Django 1.2 csrf problem

I`m trying to upload files to Django with SWFUpload. Found this article Django with SWFUpload. But found one problem. In Django 1.2 a csrf requires a csrf token to be send on every form submit, and it includes files that are send with SWFUpload.So uploading doesnt until i turn off csrf ( globally or for view using #csrf_exempt decorator). Is there a better way to handle this rather than turning off csrf?
I know that i can pass custom data with SWFUpload post_params: {"csrfmiddlewaretoken" : ""},. But i don`t know how to get only value of csrf token in template, not a full input tag.
To retrieve the csrf token itself, you'll need to resort to using some of Django's internals. First off, include this line at the top of your view.
from django.middleware.csrf import get_token
Now, when passing parameters to your template, do something like
def my_view(request):
return render_to_response("index.html", {"csrf_token": get_token(request)})
In your template, just reference the token with {{ csrf_token }}.