Django API Testing : csrf exempt - python

I'm getting a "Forbidden (CSRF cookie not set.): /user/admin/sign-up" error whenever I test class based views. When I change those views to functional based views with #csrf_exempt on top of the function declaration, it works.
Postman POST Request:
localhost:8000/admin/sign-up
body : {'email' : 'email#gmail.com', 'password' : 123123}
URL path patterns:
...
path(‘/admin/sign-up’, views.AdminSignUpView),
...
Views.py
#csrf_exempt
def token_verification(request,**kwargs):
if request.method == “POST”:
id = kwargs.get(‘id’)
token = kwargs.get(‘token’)
user = User.objects.get(id = id)
redirect_url = ‘/eval/intro’
is_valid = user_activation_token.check_token(user,token)
if is_valid:
user.is_active = True
user.save()
return HttpResponseRedirect(redirect_url,status = 200)
else:
return HttpResponse(status = 403)
class AdminSignInView(View):
#csrf_exempt
def post(self,request):
data = json.loads(request.body)
try:
if User.objects.filter(name = data[‘email’]).exists():
user = User.objects.get(name=data[‘email’])
if bcrypt.checkpw(data[‘password’].encode(‘utf-8’),user.password.encode(‘utf-8’)):
token = jwt.encode({‘email’:data[‘email’]}, SECRET, algorithm = HASH).decode(‘utf-8’)
return JsonResponse({ ‘token’ : token }, status = 200)
return JsonResponse({ ‘message’ : ‘INVALID_USER’ }, status = 401)
return JsonResponse({ ‘message’ : ‘INVALID_USER’ }, status = 401)
except KeyError:
return JsonResponse({ ‘message’ : ‘INVALID_KEYS’ }, status = 400)
class AdminSignUpView(View):
#csrf_exempt
def post(self,request):
try:
data = json.loads(request.body)
if not User.objects.filter(email = data[‘email’]).exists:
password = bcrypt.hashpw(data[‘password’].encode(‘utf-8’),bcrypt.gensalt())
crypted = password.decode(‘utf-8’)
User.objects.create(
name = data[‘name’],
password = bcrypt,
email = data[‘email’],
auth_id = data[‘auth_id’]
)
return HttpResponse(status = 200)
except KeyError:
return JsonResponse({ ‘message’ : ‘INVALID_KEYS’ },status = 4000)
Models.py
class User(models.Model):
name = models.CharField(max_length = 50)
email = models.EmailField(max_length = 200,unique = True, blank = False)
department = models.ForeignKey('Department', on_delete = models.SET_NULL, null = True)
is_active = models.BooleanField(default=False)
question = models.ManyToManyField('eval.Question',through='UserQuestion')
auth = models.ForeignKey('Auth', on_delete = models.SET_NULL, null = True)
class Meta:
db_table = 'users'
token_verification view, which is written in function based, works fine but the last two raised an error. I think the fact that the decorator only goes on top of the function brings up this error, but I'm not sure why #csrf_exempt is necessary for some views.
I have no clue why I'm getting the csrf issue at this time.

I believe the problem is where you're adding the #csrf_exempt.
Django perform the csrf validation before it reaches post
You should check your Django version flowchart to find which method you should override on your View to add the csrf_exempt decorator.
https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/#django.views.generic.base.View.setup
https://docs.djangoproject.com/en/1.8/ref/class-based-views/base/#django.views.generic.base.View
I believe the code bellow should work for django versions < 2.2
#method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(AdminSignInView, self).dispatch(request, *args, **kwargs)

Related

Why all permissions checks?

I am new in django and drf
in my project I have two group of permissions
1.normal_user group : with view_issue,view_project,view_analyzeissue
2.manager_user : with all permission as possible
i have some views that check some permissions
for example IssuesViewApi view, this view need to NormalUserPermissions
so i created new group with composition of permissions in my tests and send request to the view
my new group have view_issue,change_issue
when i send request to the IssuesViewApi i get 403 response
i have a NormalUserPermissions class
class NormalUserPermissions(permissions.BasePermission):
def has_permission(self, request: Request, view):
if request.user.has_perms(get_group_permissions("normal_user")):
return True
return False
class IssuesViewApi(generics.ListAPIView):
class IssueFilter(FilterSet):
labels = CharFilter(field_name="labels", lookup_expr='contains')
project_id = NumberFilter(field_name="project__id", lookup_expr='exact')
user_name = CharFilter(field_name="users__username", lookup_expr='exact')
start_date = DateFilter(field_name="updated_at", lookup_expr='gte')
end_date = DateFilter(field_name="updated_at", lookup_expr='lte')
class Meta:
model = Issue
fields = ["iid", 'is_analyzed', 'project_id', 'labels', 'user_name', 'start_date', 'end_date']
permission_classes = [IsAuthenticated, NormalUserPermissions]
http_method_names = ['get']
pagination_class = StandardPagination
queryset = Issue.objects.all()
serializer_class = IssueSerialize
filter_backends = [OrderingFilter, DjangoFilterBackend]
filterset_class = IssueFilter
ordering_fields = ['iid', 'weight'] # order fields depend on user request
ordering = ['iid'] # default order value
def get(self, request, *args, **kwargs):
response = super(IssuesViewApi, self).get(request, *args, **kwargs)
return Response({
'data': {
'issues': response.data['results'],
},
'paginationInfo': {
"count": response.data['count'],
"next_page": response.data['next'],
"previous_page": response.data['previous'],
"total_pages": self.paginator.page.paginator.num_pages
}
})
def test_create_custom_group_and_filter_issues_and_update_issue(self):
self.run_fake_discovery()
user = self.get_user()
user.groups.add(Group.objects.get_by_natural_key("manager_user"))
self.login(username=user.username, password="123456789")
add_group_url = reverse('group-add')
group_name = "new_group"
group_permissions = list(Permission.objects.filter(codename__in=['view_issue', 'change_issue']).all().values_list('id', flat=True))
response = self.client.post(add_group_url, data=json.dumps({'name': group_name, 'permissions': group_permissions}), content_type=self.CONTENT_TYPE)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(Group.objects.filter(name=group_name).exists())
sync_user_groups_url = reverse('sync-users-and-groups')
test_user = User.objects.get(username='testuser')
response = self.client.post(sync_user_groups_url, data=json.dumps({'group_name': group_name, 'users': [test_user.id]}), content_type=self.CONTENT_TYPE)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(test_user.groups.filter(name=group_name).exists())
response=self.logout()
self.assertEqual(response.status_code,status.HTTP_200_OK)
self.login(username=test_user.username, password='123456789')
filter_issue_url = reverse('issue-filter')
filter_issue_response = self.client.get(filter_issue_url, data={'username': user.username}, content_type=self.CONTENT_TYPE)
self.assertEqual(filter_issue_response.status_code, status.HTTP_200_OK)
Why all permissions checks ?
Im going to when user has view_issue permission then get response with 200 status

Saving FieldIn Django Via API Call

I'm trying to create a new CustomerDetail object whenever an api is called.But the issue is, Whenever I try to create something for the favorite meal multi-selectfield, I get this error:
MultiValueDictKeyError at /api/customer/favorite_meal/
"'favorite_meal'"
This is the api:
#csrf_exempt
def favorite_meal(request):
if request.method == "POST":
access_token = AccessToken.objects.get(token = request.GET.get("access_token"),
expires__gt = timezone.now())
customer = access_token.user.customer
details = CustomerDetailSerializer(
CustomerDetails.objects.create(
customer = customer,
favorite_mean = request.POST["favorite_meal"]
))
return JsonResponse({"status" : "success"})
Here are my models:
class CustomerDetails(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='customer')
TYPE = (
('Time', (
('Breakfast', 'Breakfast'),
('Lunch', 'Lunch'),
('Dinner', 'Dinner'),
)),
)
favorite_meal = MultiSelectField(choices=TYPE)
interested_in = MultiSelectField(choices=CATEGORIES)
likes = models.ManyToManyField('Product')
completed_orders = models.IntegerField(default = "0", blank=True)
shares = models.IntegerField(default = "0", blank=True)
average_order = models.FloatField(default = "0.0", blank=True)
def __str__(self):
return self.customer.user.get_full_name()
In the request, I'm trying to select breakfast and lunch via the api. How would I do this?
Sending Params:
The status says success but, there is no Customer data in details
The MultiValueDictKeyError error raises when you are trying to access favorite_meal from request.POST, but the favorite_meal doesn't exist in request.POST
Try this
#csrf_exempt
def favorite_meal(request):
if request.method == "POST":
if not 'access_token' in request.POST:
return JsonResponse({"status": "'access_token' missing in POST payload"})
access_token = AccessToken.objects.get(token=request.POST.get("access_token"),
expires__gt=timezone.now())
customer = access_token.user.customer
if not 'favorite_meal' in request.POST and not request.POST["favorite_meal"]:
return JsonResponse({"status": "'favorite_meal' missing in POST payload"})
details = CustomerDetailSerializer(
CustomerDetails.objects.create(
customer=customer,
favorite_mean=request.POST["favorite_meal"]
))
return JsonResponse({"status": "success"})
Screenshot
UPDATE
#csrf_exempt
def favorite_meal(request):
if request.method == "POST":
if not 'access_token' in request.POST:
return JsonResponse({"status": "'access_token' missing in POST payload"})
access_token = AccessToken.objects.get(token=request.POST.get("access_token"),
expires__gt=timezone.now())
customer = access_token.user.customer
if not 'favorite_meal' in request.POST and not request.POST["favorite_meal"]:
return JsonResponse({"status": "'favorite_meal' missing in POST payload"})
for favorite_meal in request.POST["favorite_meal"]:
details = CustomerDetailSerializer(
CustomerDetails.objects.create(
customer=customer,
favorite_mean=favorite_meal
))
return JsonResponse({"status": "success"})

Django Restframework _ custom authentication

I wrote some code for custom authentication with this structure:
serializers.py
class LoginSerializer(serializers.Serializer):
first_token = serializers.CharField()
phonenumber = serializers.CharField()
token = serializers.CharField(max_length=255, read_only=True)
views .py
class LoginView(APIView):
serializer_class = LoginSerializer
permission_classes = (AllowAny,)
def post(self, request, format=None):
phonenumber = request.data.get('phonenumber', None)
first_token = request.data.get('first_token', None)
try:
x = User.objects.get(phonenumber=phonenumber)
except x.DoesNotExist:
return Response('user does not exists')
if first_token == x.first_token.token:
user = authenticate(phonenumber=phonenumber)
login_user = login(request, user)
user_info = {
'phonenumber': user.phonenumber,
'username': user.username,
'token': user.token,
'is_admin':user.is_admin,
}
return Response(user_info, status=status.HTTP_200_OK)
urls.py
urlpatterns = [
re_path(r'^login/$', views.LoginView.as_view(), name='login'),
]
so, authentication and login is successful and user logs in. but when i try to go another page testframework doesnt store the authentication. I made a custom authentication already .
auth.py
class PhoneAuthentication(authentication.BaseAuthentication):
authentication_header_prefix = 'Token'
def authenticate(self, request):
request.user = None
auth_header = authentication.get_authorization_header(request).split()
auth_header_prefix = self.authentication_header_prefix.lower()
if not auth_header:
return None
if len(auth_header) == 1:
return None
elif len(auth_header) > 2:
return None
prefix = auth_header[0].decode('utf-8')
token = auth_header[1].decode('utf-8')
if prefix.lower() != auth_header_prefix:
return None
return self._authenticate_credentials(request, token)
def _authenticate_credentials(self, request, token):
try:
payload = jwt.decode(token, settings.SECRET_KEY)
except:
raise exceptions.AuthenticationFailed("invalid authentication . could not decode token")
try:
user = User.objects.get(pk=payload['id'])
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return(user, token)
I think the best way to do it is to subscribe the view ObtainAuthToken that is default of DRF.

custom authentication not working in django-tastypie

My question is, how do i write my own custom authentication correctly??
i have tried to follow this:
http://django-tastypie.readthedocs.org/en/latest/authentication.html#implementing-your-own-authentication-authorization
I have implemented basic method,
api.py
def prepareResponce(responceData):
"""Prepares a Json responce with status 200"""
response = JsonResponse(responceData)
return response # {"foo": "bar"}
class CustomBasicAuthentication(BasicAuthentication):
userID = None
userType = None
userAccess = None
userName = None
def is_authenticated(self, request, **kwargs):
if 'admin' in request.user.username:
return prepareResponce({'logged in': 'Admin' })
#return True
return prepareResponce({'not allowed for':userName })
def get_identifier(self, request):
return request.user.username
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
authentication = CustomBasicAuthentication()
allowed_methods = ['get', 'post']
when i call API providing admin's username and password it's always return the else part. where am i did wrong ?
You missed return and You don't call parent is_authenticated function:
def is_authenticated(self, request, **kwargs):
super(CustomBasicAuthentication, self).is_authenticated(request, **kwargs)
if 'admin' == request.user.username:
return prepareResponce({'logged in': 'Admin' })
return prepareResponce({'not allowed for': self.userName })

how to fix the 'AnonymousUser' object has no attribute 'profile' error?

I'm writing a chat app for a hypothetical social network but when I try to open the chat page I give the following error 'AnonymousUser' object has no attribute 'profile' error .
I think there may be problem in the models file but I can't really figure out how to fix it and I'm really confused now!? can anyone give any suggestions??
parts of the chat views.py
def index(request):
if request.method == 'POST':
print request.POST
request.user.profile.is_chat_user=True
logged_users = []
if request.user.username and request.user.profile.is_chat_user:
context = {'logged_users':logged_users}
cu = request.user.profile
cu.is_chat_user = True
cu.last_accessed = utcnow()
cu.save()
return render(request, 'djangoChat/index.html', context)
try:
eml = request.COOKIES[ 'email' ]
pwd = request.COOKIES[ 'password' ]
except KeyError:
d = {'server_message':"You are not logged in."}
query_str = urlencode(d)
return HttpResponseRedirect('/login/?'+query_str)
try:
client = Vertex.objects.get(email = eml)
context = {'logged_users':logged_users}
cu = request.user.profile
cu.is_chat_user = True
cu.last_accessed = utcnow()
cu.save()
if client.password != pwd:
raise LookupError()
except Vertex.DoesNotExist:
sleep(3)
d = {'server_message':"Wrong username or password."}
query_str = urlencode(d)
return HttpResponseRedirect('/login/?'+query_str)
return render_to_response('djangoChat/index.html',
{"USER_EMAIL":eml,request.user.profile.is_chat_user:True},
context_instance=RequestContext(request))
#csrf_exempt
def chat_api(request):
if request.method == 'POST':
d = json.loads(request.body)
msg = d.get('msg')
user = request.user.username
gravatar = request.user.profile.gravatar_url
m = Message(user=user,message=msg,gravatar=gravatar)
m.save()
res = {'id':m.id,'msg':m.message,'user':m.user,'time':m.time.strftime('%I:%M:%S %p').lstrip('0'),'gravatar':m.gravatar}
data = json.dumps(res)
return HttpResponse(data,content_type="application/json")
# get request
r = Message.objects.order_by('-time')[:70]
res = []
for msgs in reversed(r) :
res.append({'id':msgs.id,'user':msgs.user,'msg':msgs.message,'time':msgs.time.strftime('%I:%M:%S %p').lstrip('0'),'gravatar':msgs.gravatar})
data = json.dumps(res)
return HttpResponse(data,content_type="application/json")
def logged_chat_users(request):
u = Vertex.objects.filter(is_chat_user=True)
for j in u:
elapsed = utcnow() - j.last_accessed
if elapsed > datetime.timedelta(seconds=35):
j.is_chat_user = False
j.save()
uu = Vertex.objects.filter(is_chat_user=True)
d = []
for i in uu:
d.append({'username': i.username,'gravatar':i.gravatar_url,'id':i.userID})
data = json.dumps(d)
return HttpResponse(data,content_type="application/json")
and parts of my chat models:
class Message(models.Model):
user = models.CharField(max_length=200)
message = models.TextField(max_length=200)
time = models.DateTimeField(auto_now_add=True)
gravatar = models.CharField(max_length=300)
def __unicode__(self):
return self.user
def save(self):
if self.time == None:
self.time = datetime.now()
super(Message, self).save()
def generate_avatar(email):
a = "http://www.gravatar.com/avatar/"
a+=hashlib.md5(email.lower()).hexdigest()
a+='?d=identicon'
return a
def hash_username(username):
a = binascii.crc32(username)
return a
# the problem seems to be here ??!
User.profile = property(lambda u: Vertex.objects.get_or_create(user=u,defaults={'gravatar_url':generate_avatar(u.email),'username':u.username,'userID':hash_username(u.username)})[0])
and finally parts of the another app(ChatUsers):
class Vertex(models.Model,object):
user = models.OneToOneField(User)
password = models.CharField(max_length=50)
#user_id = models.CharField(max_length=100)
username = models.CharField(max_length=300)
userID =models.IntegerField()
Message = models.CharField(max_length=500)
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
email = models.EmailField(max_length=75)
is_chat_user = models.BooleanField(default=False)
gravatar_url = models.CharField(max_length=300,null=True, blank=True)
last_accessed = models.DateTimeField(auto_now_add=True)
Because that user has not logged in yet. Django treat them as AnonymousUser and AnonymousUser does not have the profile property.
If the view is only for logged in user, you can add the login_required decorator to the view function to force the login process. Otherwise, you need to judge whether a user is anonymous with the is_authenticated function.
Reference: Using the Django authentication system

Categories