Skip to content

Commit 5c589e2

Browse files
authored
Add DomainControlValidation class with a few basic DCV methods. (#218)
* Add DCV class with a few basic DCV methods. I only added the ones I needed, but I think this may still be useful as a starting point. * Address review comments Added unit tests, updated imports, and fixed typing typo * Fix failing test in test_client.py This test no longer passes because the assertDict methods have been removed in the latest python. * Run pre-commit and fix issues * Fix tests for Python <3.9
1 parent 9a8c86b commit 5c589e2

File tree

3 files changed

+484
-4
lines changed

3 files changed

+484
-4
lines changed

cert_manager/dcv.py

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""Define the cert_manager.dcv.DomainControlValidation class."""
2+
3+
from http import HTTPStatus
4+
5+
from requests.exceptions import HTTPError
6+
7+
from ._endpoint import Endpoint
8+
9+
10+
class DomainControlValidation(Endpoint):
11+
"""Query the Sectigo Cert Manager REST API for Domain Control Validation (DCV) data."""
12+
13+
def __init__(self, client, api_version="v1"):
14+
"""Initialize the class.
15+
16+
:param object client: An instantiated cert_manager.Client object
17+
:param string api_version: The API version to use; the default is "v1"
18+
"""
19+
super().__init__(client=client, endpoint="/dcv", api_version=api_version)
20+
21+
def search(self, **kwargs):
22+
"""Search the DCV statuses of domains.
23+
24+
:param dict kwargs the following search keys are supported:
25+
position, size, domain, org, department, dcvStatus, orderStatus, expiresIn
26+
27+
See
28+
https://www.sectigo.com/uploads/audio/Certificate-Manager-20.1-Rest-API.html#resources-dcv-statuses
29+
30+
:return list: a list of DCV statuses
31+
"""
32+
url = self._url("validation")
33+
result = self._client.get(url, params=kwargs)
34+
35+
return result.json()
36+
37+
def get_validation_status(self, domain: str):
38+
"""Get the DCV statuses of a domain.
39+
40+
:param dict kwargs the following search keys are supported:
41+
position, size, domain, org, department, dcvStatus, orderStatus, expiresIn
42+
43+
See
44+
https://www.sectigo.com/uploads/audio/Certificate-Manager-20.1-Rest-API.html#resources-dcv-status
45+
46+
:return list: the DCV status for the domain
47+
"""
48+
url = self._url("validation", "status")
49+
data = {"domain": domain}
50+
51+
try:
52+
result = self._client.post(url, data=data)
53+
except HTTPError as exc:
54+
status_code = exc.response.status_code
55+
if status_code == HTTPStatus.BAD_REQUEST:
56+
err_response = exc.response.json()
57+
raise ValueError(err_response["description"]) from exc
58+
raise exc
59+
60+
return result.json()
61+
62+
def start_validation_cname(self, domain: str):
63+
"""Start Domain Control Validation using the CNAME method.
64+
65+
See
66+
https://www.sectigo.com/uploads/audio/Certificate-Manager-20.1-Rest-API.html#resources-dcv-start-http
67+
68+
:param string domain: The domain to validate
69+
70+
:return response: a dictionary containing
71+
host: Where the validation will expect the CNAME to live on the server
72+
point: Where the CNAME should point to
73+
"""
74+
url = self._url("validation", "start", "domain", "cname")
75+
data = {"domain": domain}
76+
77+
try:
78+
result = self._client.post(url, data=data)
79+
except HTTPError as exc:
80+
status_code = exc.response.status_code
81+
if status_code == HTTPStatus.BAD_REQUEST:
82+
err_response = exc.response.json()
83+
raise ValueError(err_response["description"]) from exc
84+
raise exc
85+
86+
return result.json()
87+
88+
def submit_validation_cname(self, domain: str):
89+
"""Finish Domain Control Validation using the CNAME method.
90+
91+
See
92+
https://www.sectigo.com/uploads/audio/Certificate-Manager-20.1-Rest-API.html#resources-dcv-submit-cname
93+
94+
:param string domain: The domain to validate
95+
96+
:return response: a dictionary containing
97+
status: The status of the validation
98+
orderStatus: The status of the validation request
99+
message: An optional message to help with debugging
100+
"""
101+
url = self._url("validation", "submit", "domain", "cname")
102+
data = {"domain": domain}
103+
104+
try:
105+
result = self._client.post(url, data=data)
106+
except HTTPError as exc:
107+
status_code = exc.response.status_code
108+
if status_code == HTTPStatus.BAD_REQUEST:
109+
err_response = exc.response.json()
110+
raise ValueError(err_response["description"]) from exc
111+
raise exc
112+
113+
return result.json()

tests/test_client.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,9 @@ def test_params(self):
340340
self.assertEqual(resp.json(), json_data)
341341
self.assertEqual(len(responses.calls), 1)
342342
self.assertEqual(url_plain, self.test_url)
343-
self.assertDictContainsSubset(
344-
params,
345-
dict(responses.parse_qsl(query_string))
346-
)
343+
query_params = dict(responses.parse_qsl(query_string))
344+
# See https://stackoverflow.com/questions/20050913
345+
self.assertEqual(query_params, {**params, **query_params})
347346

348347
@responses.activate
349348
def test_failure(self):

0 commit comments

Comments
 (0)