Browse Source

fix(auth): handle authentication headers with multiple colons

We didn't handle HTTP Authentication headers with no or more than
one colon correctly. Added tests and fix.

Closes #4
Nils Wisiol 8 years ago
parent
commit
6ef8dab7bb

+ 1 - 1
api/desecapi/authentication.py

@@ -46,7 +46,7 @@ class BasicTokenAuthentication(BaseAuthentication):
         try:
             user, key = base64.b64decode(basic).decode(HTTP_HEADER_ENCODING).split(':')
             token = self.model.objects.get(key=key)
-        except self.model.DoesNotExist:
+        except:
             raise exceptions.AuthenticationFailed('Invalid basic auth token')
 
         if not token.user.is_active:

+ 68 - 0
api/desecapi/tests/testdynupdateauthentication.py

@@ -0,0 +1,68 @@
+from django.core.urlresolvers import reverse
+from rest_framework import status
+from rest_framework.test import APITestCase
+from .utils import utils
+import httpretty
+import base64
+from django.conf import settings
+
+
+class DynUpdateAuthenticationTests(APITestCase):
+
+    def setCredentials(self, username, password):
+        self.client.credentials(
+            HTTP_AUTHORIZATION='Basic ' + base64.b64encode((username + ':' + password).encode()).decode())
+
+    def setUp(self):
+        if not hasattr(self, 'owner'):
+            self.username = utils.generateRandomString(12)
+            self.password = utils.generateRandomString(12)
+            self.user = utils.createUser(self.username, self.password)
+            self.token = utils.createToken(user=self.user)
+            self.setCredentials(self.username, self.password)
+            self.url = reverse('dyndns12update')
+
+            self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token)
+            self.domain = utils.generateDynDomainname()
+            url = reverse('domain-list')
+            data = {'name': self.domain, 'dyn': True}
+            response = self.client.post(url, data)
+            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+            self.assertEqual(response.data['dyn'], True)
+
+            httpretty.enable()
+            httpretty.register_uri(httpretty.POST, settings.POWERDNS_API + '/zones')
+            httpretty.register_uri(httpretty.PATCH, settings.POWERDNS_API + '/zones/' + self.domain)
+
+    def testSuccessfulAuthentication(self):
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data, 'good')
+
+    def testWrongUsername(self):
+        self.setCredentials('wrong', self.password)
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+    def testWrongPassword(self):
+        self.setCredentials(self.username, 'wrong')
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+    def testDoubleColonInAuthentication(self):
+        self.client.credentials(
+            HTTP_AUTHORIZATION='Basic ' + base64.b64encode((self.username + ':' + self.password + ':bullshit').encode()).decode())
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+    def testlNoColonInAuthentication(self):
+        self.client.credentials(
+            HTTP_AUTHORIZATION='Basic ' + base64.b64encode((self.username + '' + self.password).encode()).decode())
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+    def testNoValidEncoding(self):
+        self.client.credentials(HTTP_AUTHORIZATION='Basic bull[%]shit')
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+

+ 2 - 2
api/desecapi/tests/utils.py

@@ -28,11 +28,11 @@ class utils(object):
     """
 
     @classmethod
-    def createUser(cls, username=None):
+    def createUser(cls, username=None, password=None):
         if username is None:
             username = cls.generateUsername()
         user = User(email=username)
-        user.plainPassword = cls.generateRandomString(size=12)
+        user.plainPassword = cls.generateRandomString(size=12) if password is None else password
         user.set_password(user.plainPassword)
         user.save()
         return user