From ec584b7aab792de45306c7b56a18471b984f8446 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 1 Feb 2021 14:13:58 +0000 Subject: [PATCH] fixed password update not working --- README.md | 17 +++++++++++++++++ back_latienda/urls.py | 1 - core/tests.py | 21 +++++++++++++++------ core/views.py | 37 +++++++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d3976f0..cbcbdf0 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,23 @@ To load initial location data use: `python manage.py addgeo` ## Endpoints +### Authentication + +Implemented using `djangorestframework-simplejwt` + + +New token pair endpoint: `/api/v1/token/` + +Response: +```json +{ + "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMjI3MTcwNSwianRpIjoiZDU4YTgzYzFkYzFkNDI5MTljMGQ0NzcxNzljNzUxYTQiLCJ1c2VyX2lkIjo4fQ.yln80W5lONSyHwwqF4qBBHteqLuRfdLLWuaQANr_vxc", + "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMTg4OTA1LCJqdGkiOiIzNGIxMzM3NmU4MWI0OWY5YjU3ZmUxM2M5NThmZWZkYiIsInVzZXJfaWQiOjh9.aRDCUvKj7LCvixjPLC9ghy0h7rfRwR6Lo3A7HX4kSHE" +} +``` +Refresh expired token endpoint: `/api/v1/token/refresh/` + + ### Users Endpoint url: `/api/v1/users/` diff --git a/back_latienda/urls.py b/back_latienda/urls.py index 5767a16..dcba025 100644 --- a/back_latienda/urls.py +++ b/back_latienda/urls.py @@ -27,6 +27,5 @@ urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/v1/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), - path('api/v1/token/verify/', TokenVerifyView.as_view(), name='token_verify'), path('api/v1/', include(router.urls)), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/core/tests.py b/core/tests.py index 13f8cb2..89cf9eb 100644 --- a/core/tests.py +++ b/core/tests.py @@ -26,12 +26,8 @@ class CustomUserViewSetTest(APITestCase): self.endpoint = '/api/v1/users/' self.factory = factories.CustomUserFactory self.model = models.CustomUser - # create admin user - self.admin_email = f"admin_user@mail.com" - self.password = ''.join(random.choices(string.ascii_uppercase, k = 10)) - self.user = self.factory(email=self.admin_email, password=self.password, is_active=True) # create regular user - self.reg_email = f"regular_user@mail.com" + self.reg_email = f"user@mail.com" self.password = ''.join(random.choices(string.ascii_uppercase, k = 10)) self.user = self.factory(email=self.reg_email, password=self.password, is_active=True) @@ -129,7 +125,20 @@ class CustomUserViewSetTest(APITestCase): response = self.client.put(url, data=data, format='json') # Assert forbidden code - self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # assert new password hash properly updated + # assert fields exist, and data matches + updated_user = self.model.objects.get(pk=self.user.id) + stored_value = updated_user.__dict__['password'] + hash_type, iteration, salt, stored_password_hash = stored_value.split('$') + new_password_hash = hashlib.pbkdf2_hmac( + hash_name='sha256', + password=data['password'].encode(), + salt=salt.encode(), + iterations=int(iteration), + ) + self.assertEqual(stored_password_hash, base64.b64encode(new_password_hash).decode()) def test_regular_user_cannot_modify_existing_instance(self): """Regular user cannot modify existing instance diff --git a/core/views.py b/core/views.py index 0d4119e..4db0ab7 100644 --- a/core/views.py +++ b/core/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render, get_object_or_404 from django.http import HttpResponse +from django.contrib.auth import get_user_model from rest_framework import status from rest_framework import viewsets @@ -12,13 +13,17 @@ from . import serializers from back_latienda.permissions import CustomUserPermissions # Create your views here. + +User = get_user_model() + + class CustomUserViewSet(viewsets.ModelViewSet): - model = models.CustomUser + model = User serializer_class = serializers.CustomUserReadSerializer write_serializer_class =serializers.CustomUserWriteSerializer model_name = 'custom_user' - queryset = models.CustomUser.objects.all() + queryset = User.objects.all() permission_classes = [CustomUserPermissions,] def create(self, request): @@ -45,6 +50,34 @@ class CustomUserViewSet(viewsets.ModelViewSet): except Exception as e: return Response(str(e), status=status.HTTP_500_INTERNAL_SERVER_ERROR) + def update(self, request, pk): + """ + Update CustomUser Instance + """ + try: + serializer = self.write_serializer_class( + data=request.data, + ) + if serializer.is_valid(): + # save model instance data + password = serializer.validated_data.pop('password') + instance = get_object_or_404(User, pk=pk) + + for key, value in serializer.validated_data.items(): + instance.__dict__[key] = value + + instance.set_password(password) + instance.save() + + return Response(self.serializer_class( + instance, many=False, context={'request': request}).data, + status=status.HTTP_201_CREATED) + else: + return Response( + serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE) + except Exception as e: + return Response(str(e), status=status.HTTP_500_INTERNAL_SERVER_ERROR) + def get_object(self): obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) self.check_object_permissions(self.request, obj)