Browse Source

fix(api): give 401 for dyn if username is neither email nor domain name

Peter Thomassen 6 years ago
parent
commit
5f5b819045

+ 3 - 0
api/desecapi/authentication.py

@@ -48,6 +48,9 @@ class BasicTokenAuthentication(BaseAuthentication):
         try:
             user, key = base64.b64decode(basic).decode(HTTP_HEADER_ENCODING).split(':')
             token = self.model.objects.get(key=key)
+            domain_names = token.user.domains.values_list('name', flat=True)
+            if not user in ['', token.user.email] and not user.lower() in domain_names:
+                raise Exception
         except Exception:
             raise exceptions.AuthenticationFailed(invalid_token_message)
 

+ 1 - 1
api/desecapi/tests/base.py

@@ -748,7 +748,7 @@ class DynDomainOwnerTestCase(DomainOwnerTestCase):
     def setUp(self):
         super().setUp()
         self.client_token_authorized = self.client_class()
-        self.client.set_credentials_basic_auth(self.my_domain.name, self.token.key)
+        self.client.set_credentials_basic_auth(self.my_domain.name.lower(), self.token.key)
         self.client_token_authorized.set_credentials_token_auth(self.token.key)
 
 

+ 11 - 11
api/desecapi/tests/test_authentication.py

@@ -15,18 +15,18 @@ class DynUpdateAuthenticationTestCase(DynDomainOwnerTestCase):
             self.client.set_credentials_basic_auth(authorization)
         self.assertStatus(self._get_dyndns12(), status)
 
-    def assertDynDNS12AuthenticationStatus(self, username, token, status):
-        # Note that this overwrites self.client's credentials, which may be unexpected
-        self.client.set_credentials_basic_auth(username, token)
-        self.assertDynDNS12Status(status)
-
     def test_username_password(self):
-        # FIXME the following test fails
-        # self.assertDyndns12AuthenticationStatus(self.user.get_username(), self.token.key, HTTP_200_OK)
-        self.assertDynDNS12AuthenticationStatus('', self.token.key, HTTP_200_OK)
-        self.assertDynDNS12AuthenticationStatus('wrong', self.token.key, HTTP_404_NOT_FOUND)
-        self.assertDynDNS12AuthenticationStatus('', 'wrong', HTTP_401_UNAUTHORIZED)
-        self.assertDynDNS12AuthenticationStatus(self.user.get_username(), 'wrong', HTTP_401_UNAUTHORIZED)
+        def _test_DynDNS12AuthenticationStatus(username, token, status):
+            self.client.set_credentials_basic_auth(username, token)
+            self.assertDynDNS12Status(status)
+
+        _test_DynDNS12AuthenticationStatus('', self.token.key, HTTP_200_OK)
+        _test_DynDNS12AuthenticationStatus(self.owner.get_username(), self.token.key, HTTP_200_OK)
+        _test_DynDNS12AuthenticationStatus(self.my_domain.name, self.token.key, HTTP_200_OK)
+        _test_DynDNS12AuthenticationStatus(' ' + self.my_domain.name, self.token.key, HTTP_401_UNAUTHORIZED)
+        _test_DynDNS12AuthenticationStatus('wrong', self.token.key, HTTP_401_UNAUTHORIZED)
+        _test_DynDNS12AuthenticationStatus('', 'wrong', HTTP_401_UNAUTHORIZED)
+        _test_DynDNS12AuthenticationStatus(self.user.get_username(), 'wrong', HTTP_401_UNAUTHORIZED)
 
     def test_malformed_basic_auth(self):
         for authorization in [

+ 8 - 1
api/desecapi/tests/test_dyndns12update.py

@@ -25,7 +25,7 @@ class DynDNS12UpdateTest(DynDomainOwnerTestCase):
     def test_identification_by_domain_name(self):
         self.client.set_credentials_basic_auth(self.my_domain.name + '.invalid', self.token.key)
         response = self.assertDynDNS12NoUpdate(mock_remote_addr='10.5.5.6')
-        self.assertStatus(response, status.HTTP_404_NOT_FOUND)
+        self.assertStatus(response, status.HTTP_401_UNAUTHORIZED)
 
     def test_identification_by_query_params(self):
         # /update?username=foobar.dedyn.io&password=secret
@@ -142,6 +142,13 @@ class SingleDomainDynDNS12UpdateTest(DynDNS12UpdateTest):
         self.assertEqual(response.data, 'good')
         self.assertIP(ipv4='10.5.5.6')
 
+    def test_identification_by_email(self):
+        self.client.set_credentials_basic_auth(self.owner.email, self.token.key)
+        response = self.assertDynDNS12Update(self.my_domain.name, mock_remote_addr='10.5.5.6')
+        self.assertStatus(response, status.HTTP_200_OK)
+        self.assertEqual(response.data, 'good')
+        self.assertIP(ipv4='10.5.5.6')
+
 
 class MultipleDomainDynDNS12UpdateTest(DynDNS12UpdateTest):
     NUM_OWNED_DOMAINS = 4

+ 1 - 1
api/desecapi/views.py

@@ -388,7 +388,7 @@ class DynDNS12Update(APIView):
             try:
                 domain_name = base64.b64decode(
                     get_authorization_header(r).decode().split(' ')[1].encode()).decode().split(':')[0]
-                if domain_name:
+                if domain_name and '@' not in domain_name:
                     return domain_name
             except IndexError:
                 pass