diff --git a/ceod/model/VHostManager.py b/ceod/model/VHostManager.py index 747520b..ddd8e43 100644 --- a/ceod/model/VHostManager.py +++ b/ceod/model/VHostManager.py @@ -107,7 +107,6 @@ class VHostManager: checksum = md5(username.encode('utf-8')).hexdigest() record = f"csc-verification={checksum}" - # not implemented: check domain name exists? # look up for TXT record `csc-verification` at root rootname = tldextract.extract(domain).registered_domain try: @@ -121,7 +120,6 @@ class VHostManager: if "The DNS response does not contain an answer to the question: . IN TXT" not in repr(e): raise - # TODO: handle errors separately, return errors to user print(f"{rootname} does not contain any TXT records.") return False diff --git a/tests/ceod/api/test_cloud.py b/tests/ceod/api/test_cloud.py index a21c9c3..0d7b115 100644 --- a/tests/ceod/api/test_cloud.py +++ b/tests/ceod/api/test_cloud.py @@ -127,22 +127,6 @@ def test_cloud_vhosts(cfg, client, new_user, ldap_conn): principal=uid) assert status == 400 - # invalid custom domain name (with TXT record) - custom_domain = "uwaterloo.ca" - ip2 = ip1 - status, _ = client.put( - f'/api/cloud/vhosts/{custom_domain}', json={'ip_address': ip2}, - principal=uid) - assert status == 400 - - # invalid custom domain name (without TXT record) - custom_domain2 = "google.com" - ip2 = ip1 - status, _ = client.put( - f'/api/cloud/vhosts/{custom_domain2}', json={'ip_address': ip2}, - principal=uid) - assert status == 400 - # invalid IP address domain3 = domain1 ip3 = '129.97.134.10' @@ -180,21 +164,82 @@ def test_cloud_vhosts(cfg, client, new_user, ldap_conn): status, _ = client.delete(f'/api/cloud/vhosts/{domain}', principal=uid) assert status == 200 - # TODO: valid custom domain name + # invalid custom domain name (with TXT record) + custom_domain = "uwaterloo.ca" + ip2 = ip1 + status, _ = client.put( + f'/api/cloud/vhosts/{custom_domain}', json={'ip_address': ip2}, + principal=uid) + assert status == 400 + + # invalid custom domain name (without TXT record) + custom_domain2 = "google.com" + ip2 = ip1 + status, _ = client.put( + f'/api/cloud/vhosts/{custom_domain2}', json={'ip_address': ip2}, + principal=uid) + assert status == 400 + + # custom domain setup + dns_return_mock = types.SimpleNamespace() + dns_return_mock.rrset = [types.SimpleNamespace()] + dns_return_mock.rrset[ + 0].to_text = lambda: f"csc-verification={md5(uid.encode('utf-8')).hexdigest()}" + + # valid custom domain name now_mock.return_value += datetime.timedelta(seconds=rate_limit_secs) custom_domain3 = "example.com" ip2 = '172.19.134.32' with patch.object(dns.resolver, 'resolve') as dns_mock: - dns_mock.return_value = types.SimpleNamespace() - dns_mock.return_value.rrset = [types.SimpleNamespace()] - dns_mock.return_value.rrset[0].to_text = lambda: f"csc-verification={md5(uid.encode('utf-8')).hexdigest()}" + dns_mock.return_value = dns_return_mock status, _ = client.put( f'/api/cloud/vhosts/{custom_domain3}', json={'ip_address': ip2}, principal=uid) print(status) assert status == 200 - # TODO: invalid custom domain name (valid TXT record, invalid A/AAAA record) + # new custom domain name replaces old custom domain name + now_mock.return_value += datetime.timedelta(seconds=rate_limit_secs) + custom_domain4 = custom_domain3 + ip2 = '172.19.134.32' + ip3 = '172.19.134.33' + with patch.object(dns.resolver, 'resolve') as dns_mock: + dns_mock.return_value = dns_return_mock + status, _ = client.put( + f'/api/cloud/vhosts/{custom_domain4}', json={'ip_address': ip3}, + principal=uid) + print(status) + status, data = client.get('/api/cloud/vhosts', principal=uid) + assert status == 200 + assert {'domain': custom_domain4, 'ip_address': ip3} in data['vhosts'] + assert {'domain': custom_domain4, 'ip_address': ip2} not in data['vhosts'] + + # ip address can point to both csc subdomain and also custom domain + now_mock.return_value += datetime.timedelta(seconds=rate_limit_secs) + custom_domain3 = "example.com" + ip3 = '172.19.134.33' + csc_domain = uid + '.' + members_domain + status, _ = client.put( + f'/api/cloud/vhosts/{domain1}', json={'ip_address': ip3}, + principal=uid) + assert status == 200 + status, data = client.get('/api/cloud/vhosts', principal=uid) + assert status == 200 + assert {'domain': custom_domain4, 'ip_address': ip3} in data['vhosts'] + assert {'domain': csc_domain, 'ip_address': ip3} in data['vhosts'] + + # csc-verification record for a different user fails + now_mock.return_value += datetime.timedelta(seconds=rate_limit_secs) + custom_domain3 = "example.com" + ip2 = '172.19.134.34' + with patch.object(dns.resolver, 'resolve') as dns_mock: + dns_mock.return_value = dns_return_mock + dns_mock.return_value.rrset[0].to_text = lambda: f"csc-verification={md5('dummy'.encode('utf-8')).hexdigest()}" + status, _ = client.put( + f'/api/cloud/vhosts/{custom_domain3}', json={'ip_address': ip2}, + principal=uid) + print(status) + assert status == 400 # expired members may not create vhosts expire_member(new_user, ldap_conn)