Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django APIClient login not working

I'm having problem authenticating with my Django Rest Framework API in Unit Unit Tests. The system works as expected when accessing it through the browser. I however receive a 401 HTTP status when sending a put request to the following class at the following endpoint:

class UserDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
    authentication_classes = (BasicAuthentication, TokenAuthentication)
    permission_classes = IsAuthenticated,
    queryset = CustomUser.objects.all()
    serializer_class = UserSerializer

The test below is as follows:

class AccountTests(APITestCase):

    def setUp(self):
        self.user = CustomUser.objects.create_user(email="[email protected]", password="password1", is_staff=True)
        self.user.save()
        self.user = CustomUser.objects.get(email="[email protected]")
        self.client = APIClient()

    def test_add_name(self):
        self.client.login(email="[email protected]", password='password1')
        url = reverse('customuser-detail', args=(self.user.id,))
        data = {'first_name': 'test', 'last_name': 'user'}

        self.client.login(email="[email protected]", password='password1')
        response = self.client.put(url, data, format='json')

        self.assertEqual(response.status_code, status.HTTP_200_OK)

When printing the response.data, I receive:

{u'detail': u'Authentication credentials were not provided.'}

The client.login(...) method returns true, but the credentials do not appear to be attached to the header. My experiments in the IsAuthenticated permission classes had an request.user = AnonymousUser. In the BasicAuthentication class, auth = None.

Am I missing something as regards to using BasicAuth in settings.py? Or even in the test itself?

Thanks.

like image 965
mingles Avatar asked May 29 '16 17:05

mingles


2 Answers

First, {u'detail': u'Authentication credentials were not provided.'} occurs when the credential that you "provide" doesn't match with models. (I think it is bad error message)

So, you should set user's password by set_password() method, because of encryption.

self.user = CustomUser.objects.create_user(email="[email protected]", is_staff=True)
self.user.set_password("password1")
self.user.save()

or, you can use force_login() for testing.

self.client.force_login(
    user=User.objects.first(),
    backend='django.contrib.auth.backends.ModelBackend' # one of your AUTHENTICATION_BACKENDS
)
like image 70
Seung Woon Maz Lee Avatar answered Oct 27 '22 03:10

Seung Woon Maz Lee


You may need to use force_authenticate() method for logging in,

def test_add_name(self):
    self.client.force_authenticate(self.user)        
    ........

You may consider re-writing your test-case, maybe somewhat like this,

class AccountTests(APITestCase):

    def setUp(self):
        self.user = CustomUser.objects.create_user(email="[email protected]", password="password1", is_staff=True)
        self.client = APIClient()

    def test_add_name(self):
        self.client.force_authenticate(self.user)

        url = reverse('customuser-detail', args=(self.user.id,))
        data = {'first_name': 'test', 'last_name': 'user'}
        response = self.client.put(url, data, format='json')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
like image 39
zaidfazil Avatar answered Oct 27 '22 03:10

zaidfazil