From 31e6eba517fcac3f203134615ed7c5eeaa8a408d Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 27 Mar 2026 09:55:05 -0400 Subject: [PATCH 01/13] added comment ot start off flag logic --- src/open_mpic_core/common_domain/check_parameters.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index 9f1d2ad..80410f1 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -44,6 +44,9 @@ class DcvDnsChangeValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.DNS_CHANGE] = DcvValidationMethod.DNS_CHANGE dns_record_type: DnsRecordType require_exact_match: bool = False + # Baseline Requirements don't specify case sensitivity for DNS-based validation, + # but we may want this as an option for certain CAs that require it based on their implementation + # require_exact_case: bool = True # noinspection PyNestedDecorators @field_validator("dns_record_type") From 2aedf88752c0445e82a3d77ca2efa36af369ee2c Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Mon, 30 Mar 2026 14:49:02 -0400 Subject: [PATCH 02/13] broke out case sensitivity tests to prepare for test checking case sensitivity flag --- .../open_mpic_core/test_mpic_dcv_checker.py | 71 ++++++++++++------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index 9524865..bcec6dd 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -119,30 +119,23 @@ async def check_dcv__should_perform_appropriate_check_and_allow_issuance_given_t assert dcv_response.check_passed is True @pytest.mark.parametrize( - "dcv_method, record_type, is_case_insensitive", + "dcv_method, record_type", [ - (DcvValidationMethod.WEBSITE_CHANGE, None, True), - (DcvValidationMethod.DNS_CHANGE, DnsRecordType.TXT, True), - (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CNAME, True), - (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CAA, True), - # (DcvValidationMethod.DNS_PERSISTENT, None, True), # Skipped: no challenge_value - (DcvValidationMethod.CONTACT_EMAIL_TXT, None, True), - (DcvValidationMethod.CONTACT_EMAIL_CAA, None, True), - (DcvValidationMethod.CONTACT_PHONE_TXT, None, True), - (DcvValidationMethod.CONTACT_PHONE_CAA, None, True), - # (DcvValidationMethod.IP_ADDRESS, DnsRecordType.A, False), # A records should not have letters anyway - (DcvValidationMethod.IP_ADDRESS, DnsRecordType.AAAA, True), - (DcvValidationMethod.ACME_HTTP_01, None, False), - (DcvValidationMethod.ACME_DNS_01, None, False), - (DcvValidationMethod.REVERSE_ADDRESS_LOOKUP, None, True), + (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CNAME), + (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CAA), + # (DcvValidationMethod.DNS_PERSISTENT, None), # Skipped: no challenge_value + (DcvValidationMethod.CONTACT_EMAIL_TXT, None), + (DcvValidationMethod.CONTACT_EMAIL_CAA, None), + (DcvValidationMethod.CONTACT_PHONE_TXT, None), + (DcvValidationMethod.CONTACT_PHONE_CAA, None), + # (DcvValidationMethod.IP_ADDRESS, DnsRecordType.A), # A records should not have letters anyway + (DcvValidationMethod.IP_ADDRESS, DnsRecordType.AAAA), + (DcvValidationMethod.REVERSE_ADDRESS_LOOKUP, None), ], ) - async def check_dcv__should_be_case_insensitive_for_challenge_values_for_all_validation_methods_except_acme( - self, dcv_method, record_type, is_case_insensitive, mocker + async def check_dcv__should_be_case_insensitive_for_challenge_values_for_certain_validation_methods( + self, dcv_method, record_type, mocker ): - if dcv_method == DcvValidationMethod.DNS_PERSISTENT: - pytest.skip("DNS_PERSISTENT does not use challenge_value for case sensitivity test") - dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) if dcv_method in (DcvValidationMethod.CONTACT_PHONE_TXT, DcvValidationMethod.CONTACT_PHONE_CAA): # technically this should be case-insensitive, but also it would usually have digits... @@ -151,7 +144,31 @@ async def check_dcv__should_be_case_insensitive_for_challenge_values_for_all_val dcv_request.dcv_check_parameters.challenge_value = "2001:0DB8:85A3:0000:0000:8A2E:03C0:7B34" # set up mocks prior which will return the original challenge value in the dcv_request - if dcv_method in (DcvValidationMethod.WEBSITE_CHANGE, DcvValidationMethod.ACME_HTTP_01): + self._mock_request_specific_dns_resolve_call(dcv_request, mocker) + + # set up the challenge value casing to be different from the original + dcv_request.dcv_check_parameters.challenge_value = TestMpicDcvChecker.shuffle_case( + dcv_request.dcv_check_parameters.challenge_value + ) + + dcv_response = await self.dcv_checker.check_dcv(dcv_request) + assert dcv_response.check_passed is True + + # add test for case SENSITIVITY for other certain validation methods + @pytest.mark.skip(reason="still working on this test") + @pytest.mark.parametrize( + "dcv_method, record_type", + [ + (DcvValidationMethod.ACME_HTTP_01, None), + (DcvValidationMethod.ACME_DNS_01, None), + ], + ) + async def check_dcv__should_be_case_sensitive_for_challenge_values_for_certain_validation_methods( + self, dcv_method, record_type, mocker + ): + dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) + + if dcv_method is DcvValidationMethod.ACME_HTTP_01: self._mock_request_specific_http_response(dcv_request, mocker) else: self._mock_request_specific_dns_resolve_call(dcv_request, mocker) @@ -161,17 +178,17 @@ async def check_dcv__should_be_case_insensitive_for_challenge_values_for_all_val dcv_request.dcv_check_parameters.key_authorization = TestMpicDcvChecker.shuffle_case( dcv_request.dcv_check_parameters.key_authorization ) - elif dcv_method == DcvValidationMethod.ACME_DNS_01: + else: dcv_request.dcv_check_parameters.key_authorization_hash = TestMpicDcvChecker.shuffle_case( dcv_request.dcv_check_parameters.key_authorization_hash ) - else: - dcv_request.dcv_check_parameters.challenge_value = TestMpicDcvChecker.shuffle_case( - dcv_request.dcv_check_parameters.challenge_value - ) dcv_response = await self.dcv_checker.check_dcv(dcv_request) - assert dcv_response.check_passed is is_case_insensitive + assert dcv_response.check_passed is False # should fail because casing was shuffled + + # check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_challenge_values_for_certain_validation_methods + # (DcvValidationMethod.WEBSITE_CHANGE, None, True), + # (DcvValidationMethod.DNS_CHANGE, DnsRecordType.TXT, True), # fmt: off @pytest.mark.parametrize("record_type, target_record_data, mock_record_data, should_allow_issuance", [ From 908095ca2aec5c26695d90d1ee0d94f45f087f3e Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Mon, 30 Mar 2026 14:50:14 -0400 Subject: [PATCH 03/13] removed test skip for case sensitive validation methods --- tests/unit/open_mpic_core/test_mpic_dcv_checker.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index bcec6dd..6a03fdf 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -154,8 +154,6 @@ async def check_dcv__should_be_case_insensitive_for_challenge_values_for_certain dcv_response = await self.dcv_checker.check_dcv(dcv_request) assert dcv_response.check_passed is True - # add test for case SENSITIVITY for other certain validation methods - @pytest.mark.skip(reason="still working on this test") @pytest.mark.parametrize( "dcv_method, record_type", [ From 13ff852e1215d38d5a6ba19b5173e42a00c798a0 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Mon, 30 Mar 2026 15:08:35 -0400 Subject: [PATCH 04/13] added failing test for methods that can allow a require_exact_case flag --- .../common_domain/check_parameters.py | 2 +- .../open_mpic_core/test_mpic_dcv_checker.py | 32 +++++++++++++++++-- tests/unit/test_util/valid_check_creator.py | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index 676d6eb..01017e2 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -42,7 +42,7 @@ class DcvGeneralDnsValidationParameters(DcvValidationParameters, ABC): class DcvDnsChangeValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.DNS_CHANGE] = DcvValidationMethod.DNS_CHANGE - require_exact_match: bool = False + require_exact_match: bool = False # if False, looks for a matching substring (rather than entire string) # Baseline Requirements don't specify case sensitivity for DNS-based validation, # but we may want this as an option for certain CAs that require it based on their implementation # require_exact_case: bool = True diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index 6a03fdf..41a4ab1 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -184,9 +184,35 @@ async def check_dcv__should_be_case_sensitive_for_challenge_values_for_certain_v dcv_response = await self.dcv_checker.check_dcv(dcv_request) assert dcv_response.check_passed is False # should fail because casing was shuffled - # check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_challenge_values_for_certain_validation_methods - # (DcvValidationMethod.WEBSITE_CHANGE, None, True), - # (DcvValidationMethod.DNS_CHANGE, DnsRecordType.TXT, True), + @pytest.mark.parametrize( + "dcv_method, record_type, allow_case_insensitive", + [ + (DcvValidationMethod.WEBSITE_CHANGE, None, False), + (DcvValidationMethod.WEBSITE_CHANGE, None, True), + (DcvValidationMethod.DNS_CHANGE, DnsRecordType.TXT, False), + (DcvValidationMethod.DNS_CHANGE, DnsRecordType.TXT, True), + ], + ) + async def check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_challenge_values_for_certain_validation_methods( + self, dcv_method, record_type, allow_case_insensitive, mocker + ): + if allow_case_insensitive: + dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type, require_exact_case=False) + else: + dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) + + if dcv_method is DcvValidationMethod.WEBSITE_CHANGE: + self._mock_request_specific_http_response(dcv_request, mocker) + else: + self._mock_request_specific_dns_resolve_call(dcv_request, mocker) + + dcv_request.dcv_check_parameters.challenge_value = TestMpicDcvChecker.shuffle_case( + dcv_request.dcv_check_parameters.challenge_value + ) + + # pass or fail depending on case sensitivity flag + dcv_response = await self.dcv_checker.check_dcv(dcv_request) + assert dcv_response.check_passed is allow_case_insensitive # fmt: off @pytest.mark.parametrize("record_type, target_record_data, mock_record_data, should_allow_issuance", [ diff --git a/tests/unit/test_util/valid_check_creator.py b/tests/unit/test_util/valid_check_creator.py index 226f4aa..868c4b3 100644 --- a/tests/unit/test_util/valid_check_creator.py +++ b/tests/unit/test_util/valid_check_creator.py @@ -129,7 +129,7 @@ def create_valid_reverse_address_lookup_check_request() -> DcvCheckRequest: ) @staticmethod - def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None): + def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None, require_exact_case=True) -> DcvCheckRequest: match validation_method: case DcvValidationMethod.WEBSITE_CHANGE: return ValidCheckCreator.create_valid_http_check_request() From a027722668343849a4d55a25b93ef3a31feee61d Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Tue, 31 Mar 2026 14:17:53 -0400 Subject: [PATCH 05/13] added require_exact_case flag to DCV Validation Parameters (relevant to Website Change and DNS Change methods). Added tests. Reworked DCV checker logic accordingly. --- pyproject.toml | 2 +- src/open_mpic_core/__about__.py | 2 +- .../common_domain/check_parameters.py | 16 +++++++++--- .../mpic_dcv_checker/mpic_dcv_checker.py | 25 +++++++++++++------ .../open_mpic_core/test_mpic_dcv_checker.py | 6 ++--- tests/unit/test_util/valid_check_creator.py | 14 ++++++----- 6 files changed, 44 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 83040a1..2bb2d08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ build.targets.wheel.packages = ["src/open_mpic_core"] "./tests/unit/test_util" = "open_mpic_core_test/test_util" # include tests in the wheel to facilitate integration testing in wrapper projects [tool.api] -spec_version = "3.8.0" +spec_version = "3.9.0" spec_repository = "https://github.com/open-mpic/open-mpic-specification" [tool.hatch.envs.default] diff --git a/src/open_mpic_core/__about__.py b/src/open_mpic_core/__about__.py index 76d9e7e..f0a00b3 100644 --- a/src/open_mpic_core/__about__.py +++ b/src/open_mpic_core/__about__.py @@ -1 +1 @@ -__version__ = "6.3.4" +__version__ = "6.4.0" diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index 01017e2..5c41ad8 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -18,6 +18,7 @@ class CaaCheckParameters(BaseModel): class DcvValidationParameters(BaseModel, ABC): validation_method: DcvValidationMethod + require_exact_case: bool # DNS records have 5 fields: name, ttl, class, type, rdata (which can be multipart itself) # A or AAAA: name=domain_name type=A (ip address) # CNAME: name=domain_name_x type=CNAME @@ -31,6 +32,7 @@ class DcvWebsiteChangeValidationParameters(DcvValidationParameters): url_scheme: UrlScheme = UrlScheme.HTTP http_headers: dict[str, Any] | None = None match_regex: str | None = None + require_exact_case: bool = True # TODO add optional flag to iterate up through the domain hierarchy @@ -43,9 +45,7 @@ class DcvGeneralDnsValidationParameters(DcvValidationParameters, ABC): class DcvDnsChangeValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.DNS_CHANGE] = DcvValidationMethod.DNS_CHANGE require_exact_match: bool = False # if False, looks for a matching substring (rather than entire string) - # Baseline Requirements don't specify case sensitivity for DNS-based validation, - # but we may want this as an option for certain CAs that require it based on their implementation - # require_exact_case: bool = True + require_exact_case: bool = True # noinspection PyNestedDecorators @field_validator("dns_record_type") @@ -62,6 +62,7 @@ class DcvDnsPersistentValidationParameters(DcvValidationParameters): dns_name_prefix: Literal["_validation-persist"] = "_validation-persist" issuer_domain_names: list[str] # Disclosed issuer domain names from CA's CP/CPS expected_account_uri: str # The specific account URI to validate + require_exact_case: bool = Field(default=False, strict=False) # expected_account_uri should be a URI with a scheme and host (e.g. "https://example.com/acct/123") @field_validator("expected_account_uri") @@ -87,27 +88,32 @@ class DcvContactEmailTxtValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_EMAIL_TXT] = DcvValidationMethod.CONTACT_EMAIL_TXT dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_validation-contactemail"] = "_validation-contactemail" + require_exact_case: bool = Field(default=False, strict=False) class DcvContactEmailCaaValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_EMAIL_CAA] = DcvValidationMethod.CONTACT_EMAIL_CAA dns_record_type: Literal[DnsRecordType.CAA] = DnsRecordType.CAA + require_exact_case: bool = Field(default=False, strict=False) class DcvContactPhoneTxtValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_PHONE_TXT] = DcvValidationMethod.CONTACT_PHONE_TXT dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_validation-contactphone"] = "_validation-contactphone" + require_exact_case: bool = Field(default=False, strict=False) class DcvContactPhoneCaaValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_PHONE_CAA] = DcvValidationMethod.CONTACT_PHONE_CAA dns_record_type: Literal[DnsRecordType.CAA] = DnsRecordType.CAA + require_exact_case: bool = Field(default=False, strict=False) class DcvIpAddressValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.IP_ADDRESS] = DcvValidationMethod.IP_ADDRESS dns_record_type: DnsRecordType + require_exact_case: bool = Field(default=False, strict=False) # noinspection PyNestedDecorators @field_validator("dns_record_type") @@ -121,6 +127,7 @@ def validate_record_type(cls, v: DnsRecordType) -> DnsRecordType: class DcvReverseAddressLookupValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.REVERSE_ADDRESS_LOOKUP] = DcvValidationMethod.REVERSE_ADDRESS_LOOKUP dns_record_type: Literal[DnsRecordType.PTR] = DnsRecordType.PTR + require_exact_case: bool = Field(default=False, strict=False) class DcvAcmeHttp01ValidationParameters(DcvValidationParameters): @@ -128,6 +135,7 @@ class DcvAcmeHttp01ValidationParameters(DcvValidationParameters): token: str key_authorization: str http_headers: dict[str, Any] | None = None + require_exact_case: bool = Field(default=True, strict=True) class DcvAcmeDns01ValidationParameters(DcvValidationParameters): @@ -135,11 +143,13 @@ class DcvAcmeDns01ValidationParameters(DcvValidationParameters): key_authorization_hash: str dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_acme-challenge"] = "_acme-challenge" + require_exact_case: bool = Field(default=True, strict=True) class DcvAcmeTlsAlpn01ValidationParameters(DcvValidationParameters): validation_method: Literal[DcvValidationMethod.ACME_TLS_ALPN_01] = DcvValidationMethod.ACME_TLS_ALPN_01 key_authorization_hash: str + require_exact_case: bool = Field(default=False, strict=False) DcvCheckParameters = Annotated[ diff --git a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py index 7639c17..5e67ca7 100644 --- a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py +++ b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py @@ -129,6 +129,8 @@ async def perform_general_dns_validation(self, request: DcvCheckRequest) -> DcvC validation_method, check_parameters ) + require_exact_case = check_parameters.require_exact_case + if validation_method == DcvValidationMethod.DNS_CHANGE: # DNS_CHANGE may allow for non-exact match exact_match = check_parameters.require_exact_match @@ -141,7 +143,8 @@ async def perform_general_dns_validation(self, request: DcvCheckRequest) -> DcvC ): lookup = await self.perform_dns_resolution(name_to_resolve, validation_method, dns_record_type) MpicDcvChecker.evaluate_dns_lookup_response( - dcv_check_response, lookup, validation_method, dns_record_type, expected_dns_record_content, exact_match + dcv_check_response, lookup, validation_method, dns_record_type, expected_dns_record_content, exact_match, + require_exact_case ) except dns.exception.DNSException as e: log_msg = f"DNS lookup error for {name_to_resolve}: {str(e)}. Trace ID: {request.trace_identifier}" @@ -289,11 +292,18 @@ async def evaluate_http_lookup_response( # ACME requires an exact match dcv_check_response.check_passed = challenge_value == result else: - # Case-insensitive substring check for WEBSITE_CHANGE; also checks regex if provided - dcv_check_response.check_passed = challenge_value.lower() in result.lower() + # For WEBSITE_CHANGE: substring check; case-sensitive by default, unless require_exact_case=False + require_exact_case = dcv_check_request.dcv_check_parameters.require_exact_case + if require_exact_case: + dcv_check_response.check_passed = challenge_value in result + else: + dcv_check_response.check_passed = challenge_value.lower() in result.lower() if match_regex is not None and len(match_regex) > 0: match = re.search(match_regex, result) - dcv_check_response.check_passed = challenge_value.lower() in result.lower() and match is not None + if require_exact_case: + dcv_check_response.check_passed = challenge_value in result and match is not None + else: + dcv_check_response.check_passed = challenge_value.lower() in result.lower() and match is not None dcv_check_response.details.response_status_code = http_response.status dcv_check_response.details.response_url = target_url dcv_check_response.details.response_history = response_history @@ -324,6 +334,7 @@ def evaluate_dns_lookup_response( dns_record_type: DnsRecordType, expected_dns_record_content: ExpectedDnsRecordContent | None, exact_match: bool = True, + require_exact_case: bool = False, ) -> None: if dns_response is None: dcv_check_response.check_passed = False @@ -374,10 +385,10 @@ def evaluate_dns_lookup_response( expected_dns_record_content, records_as_strings ) else: - if validation_method == DcvValidationMethod.ACME_DNS_01: - expected_dns_value = expected_dns_record_content.expected_value # case-sensitive per ACME spec + if require_exact_case: + expected_dns_value = expected_dns_record_content.expected_value else: - expected_dns_value = expected_dns_record_content.expected_value.lower() # all others case-insensitive + expected_dns_value = expected_dns_record_content.expected_value.lower() # case-insensitive records_as_strings = [record.lower() for record in records_as_strings] # exact_match=True requires at least one record matches and will fail even if whitespace is different. diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index 41a4ab1..3256bbd 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -122,7 +122,7 @@ async def check_dcv__should_perform_appropriate_check_and_allow_issuance_given_t "dcv_method, record_type", [ (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CNAME), - (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CAA), + (DcvValidationMethod.DNS_CHANGE, DnsRecordType.CAA), # TODO do we want to move this to flagged casing? # (DcvValidationMethod.DNS_PERSISTENT, None), # Skipped: no challenge_value (DcvValidationMethod.CONTACT_EMAIL_TXT, None), (DcvValidationMethod.CONTACT_EMAIL_CAA, None), @@ -197,9 +197,9 @@ async def check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_chall self, dcv_method, record_type, allow_case_insensitive, mocker ): if allow_case_insensitive: - dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type, require_exact_case=False) - else: dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) + else: + dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type, require_exact_case=True) if dcv_method is DcvValidationMethod.WEBSITE_CHANGE: self._mock_request_specific_http_response(dcv_request, mocker) diff --git a/tests/unit/test_util/valid_check_creator.py b/tests/unit/test_util/valid_check_creator.py index 868c4b3..eb17e84 100644 --- a/tests/unit/test_util/valid_check_creator.py +++ b/tests/unit/test_util/valid_check_creator.py @@ -34,22 +34,24 @@ def create_valid_caa_check_request() -> CaaCheckRequest: ) @staticmethod - def create_valid_http_check_request() -> DcvCheckRequest: + def create_valid_http_check_request(require_exact_case=True) -> DcvCheckRequest: return DcvCheckRequest( domain_or_ip_target="example.com", dcv_check_parameters=DcvWebsiteChangeValidationParameters( - http_token_path="token111_ca1.txt", challenge_value="challenge_111", url_scheme=UrlScheme.HTTP + http_token_path="token111_ca1.txt", challenge_value="challenge_111", url_scheme=UrlScheme.HTTP, + require_exact_case=require_exact_case ), ) @staticmethod - def create_valid_dns_check_request(record_type=DnsRecordType.TXT) -> DcvCheckRequest: + def create_valid_dns_check_request(record_type=DnsRecordType.TXT, require_exact_case=True) -> DcvCheckRequest: check_request = DcvCheckRequest( domain_or_ip_target="example.com", dcv_check_parameters=DcvDnsChangeValidationParameters( dns_name_prefix="_dnsauth", dns_record_type=record_type, challenge_value=f"{record_type}_challenge_111.ca1.com.", + require_exact_case=require_exact_case, ), ) return check_request @@ -129,14 +131,14 @@ def create_valid_reverse_address_lookup_check_request() -> DcvCheckRequest: ) @staticmethod - def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None, require_exact_case=True) -> DcvCheckRequest: + def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None, require_exact_case=False) -> DcvCheckRequest: match validation_method: case DcvValidationMethod.WEBSITE_CHANGE: - return ValidCheckCreator.create_valid_http_check_request() + return ValidCheckCreator.create_valid_http_check_request(require_exact_case=require_exact_case) case DcvValidationMethod.DNS_CHANGE: if record_type is None: record_type = DnsRecordType.TXT - return ValidCheckCreator.create_valid_dns_check_request(record_type) + return ValidCheckCreator.create_valid_dns_check_request(record_type, require_exact_case=require_exact_case) case DcvValidationMethod.DNS_PERSISTENT: return ValidCheckCreator.create_valid_dns_persistent_check_request() case DcvValidationMethod.ACME_HTTP_01: From 21bba3538d8f936c15d89759029713166fe09b82 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Tue, 31 Mar 2026 15:37:43 -0400 Subject: [PATCH 06/13] applied formatting to changed files --- .../mpic_dcv_checker/mpic_dcv_checker.py | 13 ++++++++++--- tests/unit/open_mpic_core/test_mpic_dcv_checker.py | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py index 5e67ca7..e4879ea 100644 --- a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py +++ b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py @@ -143,8 +143,13 @@ async def perform_general_dns_validation(self, request: DcvCheckRequest) -> DcvC ): lookup = await self.perform_dns_resolution(name_to_resolve, validation_method, dns_record_type) MpicDcvChecker.evaluate_dns_lookup_response( - dcv_check_response, lookup, validation_method, dns_record_type, expected_dns_record_content, exact_match, - require_exact_case + dcv_check_response, + lookup, + validation_method, + dns_record_type, + expected_dns_record_content, + exact_match, + require_exact_case, ) except dns.exception.DNSException as e: log_msg = f"DNS lookup error for {name_to_resolve}: {str(e)}. Trace ID: {request.trace_identifier}" @@ -303,7 +308,9 @@ async def evaluate_http_lookup_response( if require_exact_case: dcv_check_response.check_passed = challenge_value in result and match is not None else: - dcv_check_response.check_passed = challenge_value.lower() in result.lower() and match is not None + dcv_check_response.check_passed = ( + challenge_value.lower() in result.lower() and match is not None + ) dcv_check_response.details.response_status_code = http_response.status dcv_check_response.details.response_url = target_url dcv_check_response.details.response_history = response_history diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index 6422550..1d0ca63 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -199,7 +199,9 @@ async def check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_chall if allow_case_insensitive: dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) else: - dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type, require_exact_case=True) + dcv_request = ValidCheckCreator.create_valid_dcv_check_request( + dcv_method, record_type, require_exact_case=True + ) if dcv_method is DcvValidationMethod.WEBSITE_CHANGE: self._mock_request_specific_http_response(dcv_request, mocker) From 65e57681b669e45255b2ba8124741569fb947113 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 10:40:22 -0400 Subject: [PATCH 07/13] updated aiohttp dependency to address moderate and low vulnerabilities --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2bb2d08..bed417a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ dependencies = [ "requests==2.32.4", "dnspython==2.7.0", "pydantic==2.11.7", - "aiohttp==3.13.3", + "aiohttp==3.13.4", "cryptography==46.0.5", "uritools==6.0.1", ] From 3beb18d8546f3e656cf0c38c720865dc223c4dff Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 13:10:00 -0400 Subject: [PATCH 08/13] added logic to force case insensitivity for DNS Change CNAME and CAA but not TXT, with tests --- .../common_domain/check_parameters.py | 9 ++++++++- .../test_check_request_parameters.py | 19 +++++++++++++++++++ .../open_mpic_core/test_mpic_dcv_checker.py | 19 +++++++++++-------- tests/unit/test_util/valid_check_creator.py | 7 +++++-- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index 12f0148..b5a4bb9 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -2,9 +2,10 @@ from typing import Literal, Union, Any, Set, Annotated from uritools import isuri -from pydantic import BaseModel, field_validator, Field +from pydantic import BaseModel, field_validator, Field, model_validator from open_mpic_core import CertificateType, DnsRecordType, DcvValidationMethod, UrlScheme +from open_mpic_core.common_domain.enum import dns_record_type DNS_CHANGE_ALLOWED_RECORD_TYPES: Set[DnsRecordType] = {DnsRecordType.CNAME, DnsRecordType.TXT, DnsRecordType.CAA} IP_ADDRESS_ALLOWED_RECORD_TYPES: Set[DnsRecordType] = {DnsRecordType.A, DnsRecordType.AAAA} @@ -55,6 +56,12 @@ def validate_record_type(cls, v: DnsRecordType) -> DnsRecordType: raise ValueError(f"Record type must be one of {DNS_CHANGE_ALLOWED_RECORD_TYPES}, got {v}") return v + @model_validator(mode="after") + def validate_require_exact_case(self) -> 'DcvDnsChangeValidationParameters': + if self.dns_record_type is not DnsRecordType.TXT: + self.require_exact_case = False # case-sensitivity only applies to TXT records; force to False for others + return self + class DcvDnsPersistentValidationParameters(DcvValidationParameters): validation_method: Literal[DcvValidationMethod.DNS_PERSISTENT] = DcvValidationMethod.DNS_PERSISTENT diff --git a/tests/unit/open_mpic_core/test_check_request_parameters.py b/tests/unit/open_mpic_core/test_check_request_parameters.py index 5a5ffa6..89b6855 100644 --- a/tests/unit/open_mpic_core/test_check_request_parameters.py +++ b/tests/unit/open_mpic_core/test_check_request_parameters.py @@ -14,6 +14,7 @@ DcvIpAddressValidationParameters, DcvCheckParameters, ) +from open_mpic_core.common_domain.enum.dns_record_type import DnsRecordType class TestCheckRequestDetails: @@ -94,6 +95,24 @@ def check_request_parameters__should_accept_valid_uri_format_for_expected_accoun assert isinstance(details_as_object, DcvDnsPersistentValidationParameters) assert details_as_object.expected_account_uri == account_uri + # fmt:off + @pytest.mark.parametrize("record_type, is_always_case_insensitive", [ + (DnsRecordType.CNAME, True), (DnsRecordType.TXT, False), (DnsRecordType.CAA, True) + ]) + # fmt:on + def check_request_parameters__should_force_case_sensitivity_to_false_for_non_txt_dns_records( + self, record_type, is_always_case_insensitive + ): + # notice require_exact_case is true in the serialized JSON; it should be forced to False for non-TXT records + parameters_as_json = f'{{"validation_method": "dns-change", "dns_record_type": "{record_type}", "challenge_value": "test-cv", "require_exact_case": true}}' + type_adapter = TypeAdapter(DcvCheckParameters) + details_as_object: DcvCheckParameters = type_adapter.validate_json(parameters_as_json) + assert isinstance(details_as_object, DcvDnsChangeValidationParameters) + if is_always_case_insensitive: + assert details_as_object.require_exact_case is False # should be forced to False for non-TXT records + else: + assert details_as_object.require_exact_case is True + if __name__ == "__main__": pytest.main() diff --git a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py index 60eb9ca..e2dcf68 100644 --- a/tests/unit/open_mpic_core/test_mpic_dcv_checker.py +++ b/tests/unit/open_mpic_core/test_mpic_dcv_checker.py @@ -197,11 +197,11 @@ async def check_dcv__should_be_case_sensitive_unless_flagged_otherwise_for_chall self, dcv_method, record_type, allow_case_insensitive, mocker ): if allow_case_insensitive: - dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) - else: dcv_request = ValidCheckCreator.create_valid_dcv_check_request( - dcv_method, record_type, require_exact_case=True + dcv_method, record_type, require_exact_case=False ) + else: + dcv_request = ValidCheckCreator.create_valid_dcv_check_request(dcv_method, record_type) if dcv_method is DcvValidationMethod.WEBSITE_CHANGE: self._mock_request_specific_http_response(dcv_request, mocker) @@ -885,11 +885,14 @@ def evaluate_persistent_dns_response__should_return_true_given_any_record_in_the result = MpicDcvChecker.evaluate_persistent_dns_response(expected_dns_record_content, records) assert result is True, "Should pass if any record is valid" - @pytest.mark.parametrize("account_uri", [ - "acct:foo123@example.com", - "https://example.com/acct/123", - "thiscanbeanything:bar@baz.com", - ]) + @pytest.mark.parametrize( + "account_uri", + [ + "acct:foo123@example.com", + "https://example.com/acct/123", + "thiscanbeanything:bar@baz.com", + ], + ) def evaluate_persistent_dns_response__should_accept_any_spec_compliant_account_uri(self, account_uri): issuer_domain_names = ["ca.example.com"] expected_account_uri = account_uri diff --git a/tests/unit/test_util/valid_check_creator.py b/tests/unit/test_util/valid_check_creator.py index eb17e84..df62e97 100644 --- a/tests/unit/test_util/valid_check_creator.py +++ b/tests/unit/test_util/valid_check_creator.py @@ -131,14 +131,17 @@ def create_valid_reverse_address_lookup_check_request() -> DcvCheckRequest: ) @staticmethod - def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None, require_exact_case=False) -> DcvCheckRequest: + def create_valid_dcv_check_request(validation_method: DcvValidationMethod, record_type=None, require_exact_case=True) -> DcvCheckRequest: match validation_method: case DcvValidationMethod.WEBSITE_CHANGE: return ValidCheckCreator.create_valid_http_check_request(require_exact_case=require_exact_case) case DcvValidationMethod.DNS_CHANGE: if record_type is None: record_type = DnsRecordType.TXT - return ValidCheckCreator.create_valid_dns_check_request(record_type, require_exact_case=require_exact_case) + if record_type is DnsRecordType.TXT: # accept a flag for TXT; for the rest, don't... + return ValidCheckCreator.create_valid_dns_check_request(record_type, require_exact_case=require_exact_case) + else: + return ValidCheckCreator.create_valid_dns_check_request(record_type) case DcvValidationMethod.DNS_PERSISTENT: return ValidCheckCreator.create_valid_dns_persistent_check_request() case DcvValidationMethod.ACME_HTTP_01: From db9510e0d25024f6f39e417982dbe21359542735 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 13:22:45 -0400 Subject: [PATCH 09/13] updated couple other libraries to address CVEs. reworked a couple of lines of logic in DCV checker to improve test coverage. --- pyproject.toml | 4 ++-- .../mpic_dcv_checker/mpic_dcv_checker.py | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bed417a..5322872 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,11 +24,11 @@ classifiers = [ ] dependencies = [ "pyyaml==6.0.2", - "requests==2.32.4", + "requests==2.33.0", "dnspython==2.7.0", "pydantic==2.11.7", "aiohttp==3.13.4", - "cryptography==46.0.5", + "cryptography==46.0.6", "uritools==6.0.1", ] diff --git a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py index e4879ea..db1949a 100644 --- a/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py +++ b/src/open_mpic_core/mpic_dcv_checker/mpic_dcv_checker.py @@ -305,12 +305,10 @@ async def evaluate_http_lookup_response( dcv_check_response.check_passed = challenge_value.lower() in result.lower() if match_regex is not None and len(match_regex) > 0: match = re.search(match_regex, result) - if require_exact_case: - dcv_check_response.check_passed = challenge_value in result and match is not None - else: - dcv_check_response.check_passed = ( - challenge_value.lower() in result.lower() and match is not None - ) + challenge_value_found = ( + challenge_value in result if require_exact_case else challenge_value.lower() in result.lower() + ) + dcv_check_response.check_passed = challenge_value_found and match is not None dcv_check_response.details.response_status_code = http_response.status dcv_check_response.details.response_url = target_url dcv_check_response.details.response_history = response_history From f119fd26f6b9abdb34dbc33c57c9f71efe7da777 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 13:41:12 -0400 Subject: [PATCH 10/13] tweaked logic in check_parameters and added tests to force ACME case sensitivity on --- .../common_domain/check_parameters.py | 5 ++--- .../test_check_request_parameters.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index b5a4bb9..56b3586 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -5,7 +5,6 @@ from pydantic import BaseModel, field_validator, Field, model_validator from open_mpic_core import CertificateType, DnsRecordType, DcvValidationMethod, UrlScheme -from open_mpic_core.common_domain.enum import dns_record_type DNS_CHANGE_ALLOWED_RECORD_TYPES: Set[DnsRecordType] = {DnsRecordType.CNAME, DnsRecordType.TXT, DnsRecordType.CAA} IP_ADDRESS_ALLOWED_RECORD_TYPES: Set[DnsRecordType] = {DnsRecordType.A, DnsRecordType.AAAA} @@ -141,7 +140,7 @@ class DcvAcmeHttp01ValidationParameters(DcvValidationParameters): token: str key_authorization: str http_headers: dict[str, Any] | None = None - require_exact_case: bool = Field(default=True, strict=True) + require_exact_case: Literal[True] = True # ACME HTTP-01 validation is always case-sensitive, per RFC8555 class DcvAcmeDns01ValidationParameters(DcvValidationParameters): @@ -149,7 +148,7 @@ class DcvAcmeDns01ValidationParameters(DcvValidationParameters): key_authorization_hash: str dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_acme-challenge"] = "_acme-challenge" - require_exact_case: bool = Field(default=True, strict=True) + require_exact_case: Literal[True] = True # ACME DNS-01 validation is always case-sensitive class DcvAcmeTlsAlpn01ValidationParameters(DcvValidationParameters): diff --git a/tests/unit/open_mpic_core/test_check_request_parameters.py b/tests/unit/open_mpic_core/test_check_request_parameters.py index 89b6855..e998648 100644 --- a/tests/unit/open_mpic_core/test_check_request_parameters.py +++ b/tests/unit/open_mpic_core/test_check_request_parameters.py @@ -13,8 +13,8 @@ DcvContactPhoneCaaValidationParameters, DcvIpAddressValidationParameters, DcvCheckParameters, + DnsRecordType ) -from open_mpic_core.common_domain.enum.dns_record_type import DnsRecordType class TestCheckRequestDetails: @@ -113,6 +113,22 @@ def check_request_parameters__should_force_case_sensitivity_to_false_for_non_txt else: assert details_as_object.require_exact_case is True + @staticmethod + def check_request_parameters__should_disallow_setting_case_sensitivity_to_false_for_acme_dns_01(): + parameters_as_json = '{"validation_method": "acme-dns-01", "key_authorization_hash": "test-kah", "require_exact_case": false}' + type_adapter = TypeAdapter(DcvCheckParameters) + with pytest.raises(Exception) as validation_error: + type_adapter.validate_json(parameters_as_json) + assert isinstance(validation_error.value, ValueError) + + @staticmethod + def check_request_parameters__should_disallow_setting_case_sensitivity_to_false_for_acme_http_01(): + parameters_as_json = '{"validation_method": "acme-http-01", "key_authorization": "test-ka", "require_exact_case": false}' + type_adapter = TypeAdapter(DcvCheckParameters) + with pytest.raises(Exception) as validation_error: + type_adapter.validate_json(parameters_as_json) + assert isinstance(validation_error.value, ValueError) + if __name__ == "__main__": pytest.main() From 6867cc6e54d1978c4ad48a5eedf8621e07982155 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 13:42:16 -0400 Subject: [PATCH 11/13] Update tests/unit/open_mpic_core/test_check_request_parameters.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/unit/open_mpic_core/test_check_request_parameters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/open_mpic_core/test_check_request_parameters.py b/tests/unit/open_mpic_core/test_check_request_parameters.py index e998648..df72c19 100644 --- a/tests/unit/open_mpic_core/test_check_request_parameters.py +++ b/tests/unit/open_mpic_core/test_check_request_parameters.py @@ -95,11 +95,11 @@ def check_request_parameters__should_accept_valid_uri_format_for_expected_accoun assert isinstance(details_as_object, DcvDnsPersistentValidationParameters) assert details_as_object.expected_account_uri == account_uri - # fmt:off + # fmt: off @pytest.mark.parametrize("record_type, is_always_case_insensitive", [ (DnsRecordType.CNAME, True), (DnsRecordType.TXT, False), (DnsRecordType.CAA, True) ]) - # fmt:on + # fmt: on def check_request_parameters__should_force_case_sensitivity_to_false_for_non_txt_dns_records( self, record_type, is_always_case_insensitive ): From c37b55e8ae3853768a520926cece49244101b1f0 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Fri, 3 Apr 2026 14:02:39 -0400 Subject: [PATCH 12/13] added token to test for acme http 01 case sensitivity --- tests/unit/open_mpic_core/test_check_request_parameters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/open_mpic_core/test_check_request_parameters.py b/tests/unit/open_mpic_core/test_check_request_parameters.py index df72c19..77cbf87 100644 --- a/tests/unit/open_mpic_core/test_check_request_parameters.py +++ b/tests/unit/open_mpic_core/test_check_request_parameters.py @@ -123,7 +123,7 @@ def check_request_parameters__should_disallow_setting_case_sensitivity_to_false_ @staticmethod def check_request_parameters__should_disallow_setting_case_sensitivity_to_false_for_acme_http_01(): - parameters_as_json = '{"validation_method": "acme-http-01", "key_authorization": "test-ka", "require_exact_case": false}' + parameters_as_json = '{"validation_method": "acme-http-01", "token:" "test", "key_authorization": "test-ka", "require_exact_case": false}' type_adapter = TypeAdapter(DcvCheckParameters) with pytest.raises(Exception) as validation_error: type_adapter.validate_json(parameters_as_json) From 6417ff4a8d6aadbd2565cff550ac463fa549aa05 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Mon, 6 Apr 2026 12:39:18 -0400 Subject: [PATCH 13/13] modified check parameters to more correctly set require_exact_case to forced False for certain methods --- .../common_domain/check_parameters.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/open_mpic_core/common_domain/check_parameters.py b/src/open_mpic_core/common_domain/check_parameters.py index 56b3586..224e0f1 100644 --- a/src/open_mpic_core/common_domain/check_parameters.py +++ b/src/open_mpic_core/common_domain/check_parameters.py @@ -68,7 +68,7 @@ class DcvDnsPersistentValidationParameters(DcvValidationParameters): dns_name_prefix: Literal["_validation-persist"] = "_validation-persist" issuer_domain_names: list[str] # Disclosed issuer domain names from CA's CP/CPS expected_account_uri: str # The specific account URI to validate - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False @field_validator("expected_account_uri") @classmethod @@ -93,32 +93,32 @@ class DcvContactEmailTxtValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_EMAIL_TXT] = DcvValidationMethod.CONTACT_EMAIL_TXT dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_validation-contactemail"] = "_validation-contactemail" - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False class DcvContactEmailCaaValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_EMAIL_CAA] = DcvValidationMethod.CONTACT_EMAIL_CAA dns_record_type: Literal[DnsRecordType.CAA] = DnsRecordType.CAA - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False class DcvContactPhoneTxtValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_PHONE_TXT] = DcvValidationMethod.CONTACT_PHONE_TXT dns_record_type: Literal[DnsRecordType.TXT] = DnsRecordType.TXT dns_name_prefix: Literal["_validation-contactphone"] = "_validation-contactphone" - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False class DcvContactPhoneCaaValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.CONTACT_PHONE_CAA] = DcvValidationMethod.CONTACT_PHONE_CAA dns_record_type: Literal[DnsRecordType.CAA] = DnsRecordType.CAA - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False class DcvIpAddressValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.IP_ADDRESS] = DcvValidationMethod.IP_ADDRESS dns_record_type: DnsRecordType - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False # noinspection PyNestedDecorators @field_validator("dns_record_type") @@ -132,7 +132,7 @@ def validate_record_type(cls, v: DnsRecordType) -> DnsRecordType: class DcvReverseAddressLookupValidationParameters(DcvGeneralDnsValidationParameters): validation_method: Literal[DcvValidationMethod.REVERSE_ADDRESS_LOOKUP] = DcvValidationMethod.REVERSE_ADDRESS_LOOKUP dns_record_type: Literal[DnsRecordType.PTR] = DnsRecordType.PTR - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False class DcvAcmeHttp01ValidationParameters(DcvValidationParameters): @@ -154,7 +154,7 @@ class DcvAcmeDns01ValidationParameters(DcvValidationParameters): class DcvAcmeTlsAlpn01ValidationParameters(DcvValidationParameters): validation_method: Literal[DcvValidationMethod.ACME_TLS_ALPN_01] = DcvValidationMethod.ACME_TLS_ALPN_01 key_authorization_hash: str - require_exact_case: bool = Field(default=False, strict=False) + require_exact_case: Literal[False] = False DcvCheckParameters = Annotated[