csrf_exempt set but CSRF Failed: Referer checking failed - no Referer - django

I have a backend API, it's in django and deployed on Google Endpoint.
I have a post request that insert data to my DB.
I created a script to use this endpoint but I got this error:
{"detail":"CSRF Failed: Referer checking failed - no Referer."}
Regarding over posts I added the crsf_exempt decorator to my class but it did not change.
I try to add the decorator two ways:
class AddUser(APIView):
""" Create user and company from csv """
#method_decorator(csrf_exempt)
def post(self, request):
#method_decorator(csrf_exempt, name='dispatch')
class AddUser(APIView):
""" Create user and company from csv """
def post(self, request):
But both failed.
This is how I contact my endpoint:
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
Any ideas ?
Thanks
EDIT
So I tried to add authentication classes to my views but it appears to be a bad idea. This is being real trouble for me.
I tried to get the csrftoken doing like this:
client = requests.session()
# Retrieve the CSRF token first
client.get(url) # sets cookie
print(client.cookies)
if 'csrftoken' in client.cookies:
# Django 1.6 and up
csrftoken = client.cookies['csrftoken']
else:
# older versions
csrftoken = client.cookies
Thing is, I am using IAP to protect my API and I do not have any csrftoken cookie but I do have a something looking like this:
<RequestsCookieJar[<Cookie GCP_IAP_XSRF_NONCE_Q0sNuY-M83380ypJogZscg=1
for ...
How can I use this to make post request to my API ?

So this happened to me because I did not set any authentication_classes to my generic view.
When this option is not set Django automatically use the SessionBackend, which need the csrf token.
I fixed it by adding this to my view: authentication_classes = [ModelBackend, GoogleOAuth2]

#Kimor - Can you try doing this in your urls.py
from django.views.decorators.csrf import csrf_exempt
url('^test/$', csrf_exempt(views.TestView.as_view())),
The get and post methods defined on the APIView class just tell DRF how the actual view should behave, but the view method that the Django router expects is not actually instantiated until you call TestView.as_view().
source
Django REST Framework CSRF Failed: CSRF cookie not set

So after working on this project for a while this is what I learned regarding the CSRF using Django.
First of all, if you are using django templates, or in any cases where your back-end and front-end are running behind the same server the most common practice is to use session for authentication.
This is activated by default by DRF.
This means that in your DRF configuration if you do not explicitly set the DEFAULT_AUTHENTICATION_CLASSES option default authentication will be set to Session + BasicAuth.
In this configuration you'll need to manage the CSRF token as described in the documentation (https://docs.djangoproject.com/en/4.0/ref/csrf/).
If your back-end and front-end are separated as in my case, using CSRF is not the only solution or even the recommended one.
As in my case I use JWT behind IAP (Identity Aware Proxy, provided by google). I had to write my own authentication classes and then use it in my DRF conf:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'main.authentication_backend.custom_auth.IAPAuthentication'],
...
}
Here is explain how to write your own authentication class: https://www.django-rest-framework.org/api-guide/authentication/#custom-authentication.

Related

How can I pass in a CSRF token with my API requests if I don't have a user login for my Django site?

Using the Django rest framework, I have an API endpoint I created that I call within my static files that I would like to pass a CSRF token into so that I'm the only one who can access the API.
My Django site does not have users with logins.
I essentially want to do something like this in my API endpoint:
#api_view(['POST'])
def payment(request, *args, **kwargs):
if (("Authorization" not in requests.headers) or (request.headers["Authorization"] != "token")):
return Response({"Error": "Not authorized for access."})
# ...
Do I need to generate a token one time and use that repeatedly?
Or can I generate one every time the script is used?
And how can I access this csrf token in my HTML file?
I'm using class-based views and I assume I would pass it in to get_context_data, but how would I set up the API endpoint to accept this CSRF token?
I would suggest to use TokenAuthentication right from the django-restframework:
https://www.django-rest-framework.org/api-guide/authentication/
You would then pass the token in the header of all your requests
like Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
If you use the decorators from the django-restframework, you can skipp all the custom token validation, as this is done by the django-restframework.
#api_view(['POST'])
#authentication_classes([TokenAuthentication])
#permission_classes([IsAuthenticated])
def payment(request, *args, **kwargs):
# ...

Avoid csrf token in django post method

I am making part of the web app where (unlogged users, all visitors) can fill the form and I have to save that data (name, phone number, question) in database..
I am making REST using Django, but for frontend I will use React or Django, and I am making POST method in Django framework that reads JSON data from POST https request, and then I save that data to database.. But I get error CSRF verification failed. Request aborted. because I don not use CSRF token, because it is not required for this (I do not have logged users).
But I do not want to disable CSRF, because for admin page I would use this to authenticate users?
So anyone knows how to avoid using CSRF token for this method? Thanks in advance..
def saveDataToDatabase(request):
if request.method == 'POST':
json_data = json.loads(request.body)
try:
data = json_data['data']
except KeyError:
HttpResponseServerError("Malformed data!")
This is the part of method..
It's possible to disable csrf protection on a view with #csrf_exempt decorator.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def saveDataToDatabase(request):
# Your code here
More Infos on the Django doc
Have you thought about using Views to handle the requests? You may use these so you don´t have to do the next advice I´m giving you.
If the first advice wasn´t good enough, you may disable the csrf token in the settings file from Django. You need to remove (or comment) the django.middleware.csrf.CsrfViewMiddleware in the available Middleware list.
Any other question just ask. ;)

Django Rest Framework permissions outside Rest Framework view

I am using Rest Framework Token authentication. Which means I cannot know if a user is authenticated outside a rest framework view eg:(A regular django view). The Rest Framework token authentication is a custom auth system which can only be used in a rest framework view.
In a normal rest framework view, I can restrict the endpoint for authenticated users by using this:
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
But how will I do that for a regular django view. eg:
def someDjangoView(request):
'''
Note that I cannout use request.user.is_authenticated.
It will always return false as I am using rest framework token authentication.
Which means the request parameter should be of rest framework's and not django's built-in.
'''
content = {"detail": "Only authenticated users should access this"}
return JsonResponse(content)
I am stuck in a situation where I have to know if a user is authenticated (custom auth) outside a rest framework view.
Is there any way to do that?
You can use the api_view decorator to your function-based view to enable DRF:
from rest_framework.decorators import api_view, authentication_classes
#api_view(http_method_names=['GET', 'POST'])
#authentication_classes([YourTokenAuthenticationClass])
def someDjangoView(request):
print(request.user)
...
return JsonResponse(content)
DRF builds on top of the builtin Django contrib.auth user auth system. So, for regular django views, you can use the regular methods provided by contrib.auth.
DRF also supports session-based authentication (usually the default when using contrib.auth). This is ideal, for example, when you have some JavaScript code running in the browser with the user's session.
Note that I cannout use request.user.is_authenticated.
It will always return false as I am using rest framework token authentication
If you are using rest framework token authentication, then you must use views that are compatible with that. request.user.is_authenticated is part of the contrib.auth system built into django. However, you must authenticate a user for this to be True. Rest Framework does this for you. If you're not using the rest framework, you must auth the user yourself!
A simple answer may be to decorate your views to make them utilize the rest framework authentication you define:
#api_view(['GET'])
#authentication_classes(...) # if defaults are not applied
#permission_classes(...) # to apply permissions you need
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})

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 include user specific access to Django REST API in this example?

My understanding of authentication via an API is that the HTTP request sent by the client needs to include credentials, whether that be just a raw username and password (probably bad practice) or a hashed password, token, etc.
Normally in my Django views, I just use:
request.user.is_authenticated():
If I want my API to be used with an iOS app, this line of code cannot be used because it relies on sessions/cookies?
I would like to edit the following function, to allow it access to a specific user:
api_view(['GET'])
#csrf_exempt
def UserInfoAPI(request):
###if HTTP header includes name and password:###
private_info = Entry.objects.filter(user=request.user)
serializer = EntrySerializer(private_info, many=True)
return Response(serializer.data)
Is there a simple way to manually check for a username/pass in the HTTP header? I don't actually plan to use this in a production environment, but for the sake of understanding, I would like to understand how to have this function verify a username/pass from the http header.
Django REST Framework tries to determine the user that sends the request looking into the Authorization HTTP header. What you should send inside this header depends on the authentication scheme you choose. For example, if you choose BasicAuthentication, your header would be:
Authorization: Basic <"user:password" encoded in base64>
or, if you choose TokenAuthentication:
Authorization: Token <your token>
I would recommend the TokenAuthentication scheme. More schemes are listed in the docs.
To make sure only authenticated users have access to that API's endpoint, use the IsAuthenticated permission. This will check your user's credentials in the request, and if they are not correct, it will raise a HTTP 401 Unauthorized error.
Your Django REST Framework view would look something like this:
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
class UserInfo(generics.ListAPIView):
model = Entry
serializer_class = EntrySerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
queryset = super(UserInfo, self).get_queryset()
user = self.request.user
return queryset.filter(user=user)
As for the code in your iOS app, this post may be helpful.