diff --git a/ca/django_ca/extensions/serialize.py b/ca/django_ca/extensions/serialize.py
index 830829075..709e31bd2 100644
--- a/ca/django_ca/extensions/serialize.py
+++ b/ca/django_ca/extensions/serialize.py
@@ -11,7 +11,15 @@
# You should have received a copy of the GNU General Public License along with django-ca. If not, see
# .
-"""``django_ca.extensions.serialize`` contains functions to serialize extensions."""
+"""``django_ca.extensions.serialize`` contains functions to serialize extensions.
+
+NOTE::
+
+ Functions in this module return values in the order as they appear in the extensions, so that the original
+ extension can be reconstructed exactly from this serialized form.
+
+TODO:: Make sure the above is actually true.
+"""
import binascii
from typing import Any, Dict, List, Optional
@@ -191,7 +199,7 @@ def _serialize_extension( # pylint: disable=too-many-return-statements
if isinstance(value, x509.CertificatePolicies):
return _certificate_policies_serialized(value)
if isinstance(value, x509.ExtendedKeyUsage):
- return sorted([EXTENDED_KEY_USAGE_NAMES[usage] for usage in value])
+ return [EXTENDED_KEY_USAGE_NAMES[usage] for usage in value]
if isinstance(value, x509.InhibitAnyPolicy):
return value.skip_certs
if isinstance(value, x509.KeyUsage):
diff --git a/ca/django_ca/tests/acme/views/base.py b/ca/django_ca/tests/acme/views/base.py
index 32c6d5bd2..22b261628 100644
--- a/ca/django_ca/tests/acme/views/base.py
+++ b/ca/django_ca/tests/acme/views/base.py
@@ -34,8 +34,9 @@
from django_ca.acme.responses import AcmeResponseUnauthorized
from django_ca.models import AcmeAccount, CertificateAuthority, acme_slug
-from django_ca.tests.base import certs, override_tmpcadir
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
MessageTypeVar = typing.TypeVar("MessageTypeVar", bound=jose.json_util.JSONObjectWithFields)
@@ -51,7 +52,7 @@ class AcmeTestCaseMixin(TestCaseMixin):
# NOTE: PEM here is the same as AcmeAccount.pem when this cert is used for account registration
PEM = (
- certs["root-cert"]["key"]["parsed"]
+ CERT_DATA["root-cert"]["key"]["parsed"]
.public_key()
.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
.decode("utf-8")
@@ -60,7 +61,7 @@ class AcmeTestCaseMixin(TestCaseMixin):
thumbprint = "kqtZjXqX07HbrRg220VoINzqF9QXsfIkQava3PdWM8o"
ACCOUNT_ONE_CONTACT = "mailto:one@example.com"
CHILD_PEM = (
- certs["child-cert"]["key"]["parsed"]
+ CERT_DATA["child-cert"]["key"]["parsed"]
.public_key()
.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
.decode("utf-8")
@@ -238,7 +239,9 @@ def acme(
if nonce is None:
nonce = self.get_nonce()
if cert is None:
- cert = typing.cast(CertificateIssuerPrivateKeyTypes, certs[self.load_certs[0]]["key"]["parsed"])
+ cert = typing.cast(
+ CertificateIssuerPrivateKeyTypes, CERT_DATA[self.load_certs[0]]["key"]["parsed"]
+ )
if post_kwargs is None:
post_kwargs = {}
diff --git a/ca/django_ca/tests/acme/views/test_authorization.py b/ca/django_ca/tests/acme/views/test_authorization.py
index 4868b8175..0ead6b1f6 100644
--- a/ca/django_ca/tests/acme/views/test_authorization.py
+++ b/ca/django_ca/tests/acme/views/test_authorization.py
@@ -29,10 +29,11 @@
from django_ca import ca_settings
from django_ca.models import AcmeAuthorization, AcmeChallenge, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeAuthorizationViewTestCase(
AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TestCase
):
diff --git a/ca/django_ca/tests/acme/views/test_challenge.py b/ca/django_ca/tests/acme/views/test_challenge.py
index 4cb4243ad..bcd2e86be 100644
--- a/ca/django_ca/tests/acme/views/test_challenge.py
+++ b/ca/django_ca/tests/acme/views/test_challenge.py
@@ -27,10 +27,11 @@
from django_ca.models import AcmeAuthorization, AcmeChallenge, AcmeOrder
from django_ca.tasks import acme_validate_challenge
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeChallengeViewTestCase(
AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TransactionTestCase
):
diff --git a/ca/django_ca/tests/acme/views/test_directory.py b/ca/django_ca/tests/acme/views/test_directory.py
index 547732668..2551473e1 100644
--- a/ca/django_ca/tests/acme/views/test_directory.py
+++ b/ca/django_ca/tests/acme/views/test_directory.py
@@ -23,7 +23,7 @@
from freezegun import freeze_time
from django_ca.models import CertificateAuthority
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
@@ -39,7 +39,7 @@ def setUp(self) -> None:
self.ca.acme_enabled = True
self.ca.save()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_default(self) -> None:
"""Test the default directory view."""
with mock.patch("secrets.token_bytes", return_value=b"foobar"):
@@ -58,7 +58,7 @@ def test_default(self) -> None:
},
)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_named_ca(self) -> None:
"""Test getting directory for named CA."""
url = reverse("django_ca:acme-directory", kwargs={"serial": self.ca.serial})
@@ -79,7 +79,7 @@ def test_named_ca(self) -> None:
},
)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_meta(self) -> None:
"""Test the meta property."""
self.ca.website = "http://ca.example.com"
@@ -112,7 +112,7 @@ def test_meta(self) -> None:
},
)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_acme_default_disabled(self) -> None:
"""Test that fetching the default CA with ACME disabled doesn't work."""
self.ca.acme_enabled = False
@@ -130,7 +130,7 @@ def test_acme_default_disabled(self) -> None:
},
)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_acme_disabled(self) -> None:
"""Test that fetching the default CA with ACME disabled doesn't work."""
self.ca.acme_enabled = False
@@ -164,7 +164,7 @@ def test_no_ca(self) -> None:
},
)
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_ca(self) -> None:
"""Test using default CA when all CAs are expired."""
response = self.client.get(self.url)
diff --git a/ca/django_ca/tests/acme/views/test_new_account.py b/ca/django_ca/tests/acme/views/test_new_account.py
index 284dbab26..902999bdb 100644
--- a/ca/django_ca/tests/acme/views/test_new_account.py
+++ b/ca/django_ca/tests/acme/views/test_new_account.py
@@ -26,15 +26,16 @@
from django_ca.models import AcmeAccount
from django_ca.tests.acme.views.base import AcmeBaseViewTestCaseMixin
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeNewAccountViewTestCase(AcmeBaseViewTestCaseMixin[acme.messages.Registration], TestCase):
"""Test creating a new account."""
contact = "mailto:user@example.com"
- url = reverse_lazy("django_ca:acme-new-account", kwargs={"serial": certs["root"]["serial"]})
+ url = reverse_lazy("django_ca:acme-new-account", kwargs={"serial": CERT_DATA["root"]["serial"]})
message = acme.messages.Registration(contact=(contact,), terms_of_service_agreed=True)
message_cls = acme.messages.Registration
requires_kid = False
diff --git a/ca/django_ca/tests/acme/views/test_new_order.py b/ca/django_ca/tests/acme/views/test_new_order.py
index 73d3cd647..23054dae8 100644
--- a/ca/django_ca/tests/acme/views/test_new_order.py
+++ b/ca/django_ca/tests/acme/views/test_new_order.py
@@ -33,14 +33,15 @@
from django_ca.acme.messages import NewOrder
from django_ca.models import AcmeAuthorization, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeNewOrderViewTestCase(AcmeWithAccountViewTestCaseMixin[NewOrder], TestCase):
"""Test creating a new order."""
- url = reverse_lazy("django_ca:acme-new-order", kwargs={"serial": certs["root"]["serial"]})
+ url = reverse_lazy("django_ca:acme-new-order", kwargs={"serial": CERT_DATA["root"]["serial"]})
message_cls = NewOrder
def get_message(self, **kwargs: Any) -> NewOrder:
diff --git a/ca/django_ca/tests/acme/views/test_order.py b/ca/django_ca/tests/acme/views/test_order.py
index cb31542c1..38352dbea 100644
--- a/ca/django_ca/tests/acme/views/test_order.py
+++ b/ca/django_ca/tests/acme/views/test_order.py
@@ -27,10 +27,11 @@
from django_ca.acme.errors import AcmeUnauthorized
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeCertificate, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeOrderViewTestCase(AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TestCase):
"""Test retrieving an order."""
diff --git a/ca/django_ca/tests/acme/views/test_order_finalize.py b/ca/django_ca/tests/acme/views/test_order_finalize.py
index 73019823e..524c8b2dd 100644
--- a/ca/django_ca/tests/acme/views/test_order_finalize.py
+++ b/ca/django_ca/tests/acme/views/test_order_finalize.py
@@ -34,12 +34,12 @@
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeOrder
from django_ca.tasks import acme_issue_certificate
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import certs, dns, override_tmpcadir, timestamps
-from django_ca.tests.base.constants import FIXTURES_DIR
+from django_ca.tests.base.constants import CERT_DATA, FIXTURES_DIR, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
+from django_ca.tests.base.utils import dns, override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeOrderFinalizeViewTestCase(
AcmeWithAccountViewTestCaseMixin[CertificateRequest], TransactionTestCase
):
@@ -47,7 +47,7 @@ class AcmeOrderFinalizeViewTestCase(
slug = "92MPyl7jm0zw"
url = reverse_lazy(
- "django_ca:acme-order-finalize", kwargs={"serial": certs["root"]["serial"], "slug": slug}
+ "django_ca:acme-order-finalize", kwargs={"serial": CERT_DATA["root"]["serial"], "slug": slug}
)
def setUp(self) -> None:
@@ -59,7 +59,7 @@ def setUp(self) -> None:
x509.CertificateSigningRequestBuilder()
.subject_name(x509.Name([]))
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
self.order = AcmeOrder.objects.create(
@@ -213,7 +213,7 @@ def test_csr_valid_subject(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
@@ -249,7 +249,7 @@ def test_csr_subject_no_cn(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
@@ -285,7 +285,7 @@ def test_csr_subject_no_domain(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
@@ -306,7 +306,7 @@ def test_csr_subject_not_in_order(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
@@ -320,7 +320,7 @@ def test_csr_no_san(self) -> None:
csr = (
x509.CertificateSigningRequestBuilder()
.subject_name(x509.Name([]))
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
@@ -338,7 +338,7 @@ def test_csr_different_names(self) -> None:
x509.SubjectAlternativeName([dns(self.hostname), dns("example.net")]),
critical=False,
)
- .sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
+ .sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)
with self.patch("django_ca.acme.views.run_task") as mockcm:
diff --git a/ca/django_ca/tests/acme/views/test_revocation.py b/ca/django_ca/tests/acme/views/test_revocation.py
index cd0e93067..6a33f559a 100644
--- a/ca/django_ca/tests/acme/views/test_revocation.py
+++ b/ca/django_ca/tests/acme/views/test_revocation.py
@@ -30,12 +30,13 @@
from django_ca.constants import ReasonFlags
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeCertificate, AcmeOrder, Certificate
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
+from django_ca.tests.base.utils import override_tmpcadir
from django_ca.utils import get_cert_builder
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationViewTestCase(
AcmeWithAccountViewTestCaseMixin[acme.messages.Revocation], TestCase
):
@@ -80,7 +81,7 @@ def test_basic(self) -> None:
self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
- self.assertEqual(self.cert.revoked_date, timestamps["everything_valid"])
+ self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.unspecified.value)
@override_settings(USE_TZ=False)
@@ -91,7 +92,7 @@ def test_basic_with_use_tz_false(self) -> None:
self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
- self.assertEqual(self.cert.revoked_date, timestamps["everything_valid_naive"])
+ self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid_naive"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.unspecified.value)
def test_reason_code(self) -> None:
@@ -102,7 +103,7 @@ def test_reason_code(self) -> None:
self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
- self.assertEqual(self.cert.revoked_date, timestamps["everything_valid"])
+ self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.affiliation_changed.name)
def test_already_revoked(self) -> None:
@@ -132,7 +133,7 @@ def test_unknown_certificate(self) -> None:
def test_wrong_certificate(self) -> None:
"""Test sending a different certificate with the same serial."""
# Create a clone of the existing certificate with the same serial number
- pkey = certs["root-cert"]["csr"]["parsed"].public_key()
+ pkey = CERT_DATA["root-cert"]["csr"]["parsed"].public_key()
builder = get_cert_builder(self.cert.expires, serial=self.cert.pub.loaded.serial_number)
builder = builder.public_key(pkey)
builder = builder.issuer_name(self.ca.subject)
@@ -147,13 +148,13 @@ def test_wrong_certificate(self) -> None:
def test_pass_csr(self) -> None:
"""Send a CSR instead of a certificate."""
- req = X509Req.from_cryptography(certs["root-cert"]["csr"]["parsed"])
+ req = X509Req.from_cryptography(CERT_DATA["root-cert"]["csr"]["parsed"])
message = self.csr_class(certificate=jose.util.ComparableX509(req))
resp = self.acme(self.url, message, kid=self.kid)
self.assertMalformed(resp, "Could not decode 'certificate'", regex=True)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationWithAuthorizationsViewTestCase(AcmeCertificateRevocationViewTestCase):
"""Test certificate revocation by signing the request with the compromised certificate."""
@@ -166,7 +167,7 @@ def setUp(self) -> None:
)
def acme(self, *args: Any, **kwargs: Any) -> "HttpResponse":
- kwargs.setdefault("cert", certs["child-cert"]["key"]["parsed"])
+ kwargs.setdefault("cert", CERT_DATA["child-cert"]["key"]["parsed"])
kwargs["kid"] = self.child_kid
return super().acme(*args, **kwargs)
@@ -210,20 +211,20 @@ def test_non_dns_sans(self) -> None:
self.assertUnauthorized(resp, "Certificate contains non-DNS subjectAlternativeNames.")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationWithJWKViewTestCase(AcmeCertificateRevocationViewTestCase):
"""Test certificate revocation by signing the request with the compromised certificate."""
requires_kid = False
def acme(self, *args: Any, **kwargs: Any) -> "HttpResponse":
- kwargs.setdefault("cert", certs[self.default_cert]["key"]["parsed"])
+ kwargs.setdefault("cert", CERT_DATA[self.default_cert]["key"]["parsed"])
kwargs["kid"] = None
return super().acme(*args, **kwargs)
def test_wrong_signer(self) -> None:
"""Sign the request with the wrong certificate."""
- cert = certs["root-cert"]["key"]["parsed"]
+ cert = CERT_DATA["root-cert"]["key"]["parsed"]
resp = self.acme(self.url, self.message, cert=cert)
self.assertUnauthorized(resp, "Request signed by the wrong certificate.")
diff --git a/ca/django_ca/tests/acme/views/test_update_account.py b/ca/django_ca/tests/acme/views/test_update_account.py
index 671e62abd..3d245ecc7 100644
--- a/ca/django_ca/tests/acme/views/test_update_account.py
+++ b/ca/django_ca/tests/acme/views/test_update_account.py
@@ -25,10 +25,10 @@
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeUpdateAccountViewTestCase(AcmeWithAccountViewTestCaseMixin[acme.messages.Registration], TestCase):
"""Test updating and ACME account."""
diff --git a/ca/django_ca/tests/acme/views/test_view_cert.py b/ca/django_ca/tests/acme/views/test_view_cert.py
index eefb22a6d..cd955e175 100644
--- a/ca/django_ca/tests/acme/views/test_view_cert.py
+++ b/ca/django_ca/tests/acme/views/test_view_cert.py
@@ -23,10 +23,11 @@
from django_ca.models import AcmeAccount, AcmeCertificate, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
-from django_ca.tests.base import CERT_PEM_REGEX, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_PEM_REGEX, TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateViewTestCase(
AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TestCase
):
diff --git a/ca/django_ca/tests/admin/test_actions.py b/ca/django_ca/tests/admin/test_actions.py
index 648547165..aa9134d5b 100644
--- a/ca/django_ca/tests/admin/test_actions.py
+++ b/ca/django_ca/tests/admin/test_actions.py
@@ -36,9 +36,10 @@
from django_ca.constants import ReasonFlags
from django_ca.models import Certificate, X509CertMixin
from django_ca.signals import post_issue_cert, post_revoke_cert, pre_revoke_cert, pre_sign_cert
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import AdminTestCaseMixin
from django_ca.tests.base.typehints import DjangoCAModelTypeVar
+from django_ca.tests.base.utils import override_tmpcadir
if typing.TYPE_CHECKING:
from django.test.client import _MonkeyPatchedWSGIResponse as HttpResponse
@@ -252,7 +253,7 @@ def test_unknown_object(self) -> None:
self.assertRedirects(response, "/admin/")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class RevokeActionTestCase(AdminActionTestCaseMixin[Certificate], TestCase):
"""Test the revoke action."""
@@ -275,7 +276,7 @@ def assertSuccessfulRequest(self, response: "HttpResponse", *objects: Certificat
self.assertRevoked(obj)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class RevokeChangeActionTestCase(AdminChangeActionTestCaseMixin[Certificate], TestCase):
"""Test the revoke change action."""
@@ -379,7 +380,7 @@ def test_revoked(self) -> None:
self.assertRevoked(self.cert)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class ResignChangeActionTestCase(AdminChangeActionTestCaseMixin[Certificate], WebTestMixin, TestCase):
"""Test the "resign" change action."""
diff --git a/ca/django_ca/tests/admin/test_add_cert.py b/ca/django_ca/tests/admin/test_add_cert.py
index d19d1f775..e428e6bcb 100644
--- a/ca/django_ca/tests/admin/test_add_cert.py
+++ b/ca/django_ca/tests/admin/test_add_cert.py
@@ -43,8 +43,8 @@
from django_ca.models import Certificate, CertificateAuthority
from django_ca.profiles import Profile, profiles
from django_ca.tests.admin.base import AddCertificateSeleniumTestCase, CertificateModelAdminTestCaseMixin
-from django_ca.tests.base import certs, dns, override_tmpcadir, timestamps, uri
from django_ca.tests.base.assertions import assert_css
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.testcases import SeleniumTestCase
from django_ca.tests.base.typehints import HttpResponse
from django_ca.tests.base.utils import (
@@ -53,20 +53,23 @@
certificate_policies,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
freshest_crl,
issuer_alternative_name,
key_usage,
ocsp_no_check,
+ override_tmpcadir,
subject_alternative_name,
subject_key_identifier,
tls_feature,
+ uri,
)
from django_ca.typehints import SerializedExtension
from django_ca.utils import ca_storage, x509_name
-@freeze_time(timestamps["after_child"])
+@freeze_time(TIMESTAMPS["after_child"])
class AddCertificateTestCase(CertificateModelAdminTestCaseMixin, TestCase):
"""Tests for adding certificates."""
@@ -92,7 +95,7 @@ def setUp(self) -> None:
def add_cert(self, cname: str, ca: CertificateAuthority, algorithm: str = "SHA-256") -> None:
"""Add certificate based on given name with given CA."""
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals() as (pre, post):
response = self.client.post(
@@ -215,7 +218,7 @@ def test_default_ca_key_does_not_exist(self) -> None:
self.assertNotEqual(bound_field.initial, self.ca)
self.assertIsInstance(bound_field.initial, CertificateAuthority)
- @override_tmpcadir(CA_DEFAULT_CA=certs["child"]["serial"])
+ @override_tmpcadir(CA_DEFAULT_CA=CERT_DATA["child"]["serial"])
def test_cas_expired(self) -> None:
"""Do a basic get request (to test CSS etc)."""
self.ca.enabled = False
@@ -263,7 +266,7 @@ def test_add(self) -> None:
def test_empty_subject(self) -> None:
"""Test passing an empty subject with a subject alternative name."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals() as (pre, post):
response = self.client.post(
@@ -305,7 +308,7 @@ def test_empty_subject(self) -> None:
def test_subject_with_multiple_org_units(self) -> None:
"""Test creating a certificate with multiple Org Units (which is allowed)."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals() as (pre, post):
response = self.client.post(
@@ -357,7 +360,7 @@ def test_subject_with_multiple_org_units(self) -> None:
def test_add_no_common_name_and_no_subject_alternative_name(self) -> None:
"""Test posting a subject with no common name and no subject alternative name."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
cert_count = Certificate.objects.all().count()
with self.assertCreateCertSignals(False, False):
@@ -401,7 +404,7 @@ def test_add_no_common_name_and_no_subject_alternative_name(self) -> None:
def test_subject_with_multiple_country_codes(self) -> None:
"""Test creating a certificate with multiple country codes (which is not allowed)."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals(False, False):
response = self.client.post(
@@ -439,7 +442,7 @@ def test_subject_with_multiple_country_codes(self) -> None:
def test_subject_with_invalid_country_code(self) -> None:
"""Test creating a certificate with an invalid country code."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals(False, False):
response = self.client.post(
@@ -476,7 +479,7 @@ def test_subject_with_invalid_country_code(self) -> None:
def test_add_no_key_usage(self) -> None:
"""Test adding a cert with no (extended) key usage."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
cname = "test-add2.example.com"
san = "test-san.example.com"
@@ -531,7 +534,7 @@ def test_add_no_key_usage(self) -> None:
def test_add_with_password(self) -> None:
"""Test adding with a password."""
ca = self.cas["pwd"]
- csr = certs["pwd-cert"]["csr"]["pem"]
+ csr = CERT_DATA["pwd-cert"]["csr"]["pem"]
cname = "with-password.example.com"
# first post without password
@@ -640,7 +643,7 @@ def test_add_with_password(self) -> None:
"authority_information_access_0": ca.issuer_url,
"authority_information_access_1": ca.ocsp_url,
"authority_information_access_2": False,
- "password": certs["pwd"]["password"].decode("utf-8"),
+ "password": CERT_DATA["pwd"]["password"].decode("utf-8"),
},
)
self.assertRedirects(response, self.changelist_url)
@@ -773,7 +776,7 @@ def test_unparsable_csr(self) -> None:
def test_expires_in_the_past(self) -> None:
"""Test creating a cert that expires in the past."""
ca = self.cas["root"]
- csr = certs["pwd-cert"]["csr"]["pem"]
+ csr = CERT_DATA["pwd-cert"]["csr"]["pem"]
cname = "test-expires-in-the-past.example.com"
expires = datetime.now() - timedelta(days=3)
@@ -819,7 +822,7 @@ def test_expires_in_the_past(self) -> None:
def test_expires_too_late(self) -> None:
"""Test that creating a cert that expires after the CA expires throws an error."""
ca = self.cas["root"]
- csr = certs["pwd-cert"]["csr"]["pem"]
+ csr = CERT_DATA["pwd-cert"]["csr"]["pem"]
cname = "test-expires-too-late.example.com"
expires = ca.expires + timedelta(days=3)
correct_expires = ca.expires.strftime("%Y-%m-%d")
@@ -870,7 +873,7 @@ def test_invalid_cn_in_san(self) -> None:
cname = "Foo Bar"
error = "The CommonName cannot be parsed as general name. Either change the CommonName or do not include it." # NOQA
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
with self.assertCreateCertSignals(False, False):
response = self.client.post(
@@ -918,7 +921,7 @@ def test_invalid_signature_hash_algorithm(self) -> None:
response = self.client.post(
self.add_url,
data={
- "csr": certs["ed448-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["ed448-cert"]["csr"]["pem"],
"ca": self.cas["ed448"].pk,
"profile": "webserver",
"subject_0": json.dumps(
@@ -939,7 +942,7 @@ def test_invalid_signature_hash_algorithm(self) -> None:
response = self.client.post(
self.add_url,
data={
- "csr": certs["ed25519-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["ed25519-cert"]["csr"]["pem"],
"ca": self.cas["ed25519"].pk,
"profile": "webserver",
"subject_0": json.dumps(
@@ -960,7 +963,7 @@ def test_invalid_signature_hash_algorithm(self) -> None:
response = self.client.post(
self.add_url,
data={
- "csr": certs["dsa-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["dsa-cert"]["csr"]["pem"],
"ca": self.cas["dsa"].pk,
"profile": "webserver",
"subject_0": json.dumps(
@@ -981,7 +984,7 @@ def test_invalid_signature_hash_algorithm(self) -> None:
response = self.client.post(
self.add_url,
data={
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"ca": self.cas["root"].pk,
"profile": "webserver",
"subject_0": json.dumps(
@@ -1001,7 +1004,7 @@ def test_invalid_signature_hash_algorithm(self) -> None:
def test_certificate_policies_with_invalid_oid(self) -> None:
"""Test posting a certificate policies extension with an invalid OID."""
ca = self.cas["root"]
- csr = certs["root-cert"]["csr"]["pem"]
+ csr = CERT_DATA["root-cert"]["csr"]["pem"]
cert_count = Certificate.objects.all().count()
with self.assertCreateCertSignals(False, False):
@@ -1034,7 +1037,7 @@ def test_certificate_policies_with_invalid_oid(self) -> None:
def test_add_no_cas(self) -> None:
"""Test adding when all CAs are disabled."""
ca = self.cas["root"]
- csr = certs["pwd-cert"]["csr"]["pem"]
+ csr = CERT_DATA["pwd-cert"]["csr"]["pem"]
CertificateAuthority.objects.update(enabled=False)
response = self.client.get(self.add_url)
self.assertEqual(response.status_code, HTTPStatus.FORBIDDEN)
@@ -1068,7 +1071,7 @@ def test_add_no_cas(self) -> None:
def test_add_unusable_cas(self) -> None:
"""Try adding with an unusable CA."""
ca = self.cas["root"]
- csr = certs["pwd-cert"]["csr"]["pem"]
+ csr = CERT_DATA["pwd-cert"]["csr"]["pem"]
CertificateAuthority.objects.update(private_key_path="not/exist/add-unusable-cas")
# check that we have some enabled CAs, just to make sure this test is really useful
@@ -1369,7 +1372,7 @@ def test_csr_integration(self) -> None:
self.assertIs(has_content.is_displayed(), False)
self.assertIs(no_content.is_displayed(), False)
- cert = certs["all-extensions"]
+ cert = CERT_DATA["all-extensions"]
csr = self.find("textarea#id_csr")
csr.send_keys(cert["csr"]["pem"])
@@ -1404,7 +1407,7 @@ def test_paste_csr_no_subject(self) -> None:
self.initialize()
# Create a CSR with no subject
- key = certs["all-extensions"]["key"]["parsed"]
+ key = CERT_DATA["all-extensions"]["key"]["parsed"]
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([])).sign(key, hashes.SHA256())
csr_pem = csr.public_bytes(serialization.Encoding.PEM).decode()
@@ -1440,7 +1443,7 @@ def test_paste_csr_missing_delimiters(self) -> None:
"""Test that pasting a CSR shows text next to subject input fields."""
self.initialize()
- cert = certs["all-extensions"]
+ cert = CERT_DATA["all-extensions"]
csr = self.find("textarea#id_csr")
# Elements of the CSR chapter
@@ -1581,7 +1584,7 @@ def test_profile_integration(self) -> None:
self.assertEqual(self.displayed_value, [])
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AddCertificateWebTestTestCase(CertificateModelAdminTestCaseMixin, WebTestMixin, TestCase):
"""Tests for adding certificates."""
@@ -1607,7 +1610,7 @@ def test_empty_form_and_empty_cert(self) -> None:
# Fill in the bare minimum fields
form = response.forms["certificate_form"]
- form["csr"] = certs["child-cert"]["csr"]["pem"]
+ form["csr"] = CERT_DATA["child-cert"]["csr"]["pem"]
form["subject_0"] = json.dumps(
[{"key": NameOID.COMMON_NAME.dotted_string, "value": "test-empty-form.example.com"}]
)
@@ -1640,7 +1643,7 @@ def test_none_extension_and_subject_alternative_name_extension(self) -> None:
"""Test how saving the model behaves when profile has None-extension or SubjectAlternativeName."""
response = self.app.get(self.add_url, user=self.user.username)
form = response.forms["certificate_form"]
- form["csr"] = certs["child-cert"]["csr"]["pem"]
+ form["csr"] = CERT_DATA["child-cert"]["csr"]["pem"]
form["subject_0"] = json.dumps([{"key": NameOID.COMMON_NAME.dotted_string, "value": self.hostname}])
response = form.submit().follow()
self.assertEqual(response.status_code, 200)
@@ -1686,7 +1689,7 @@ def test_only_ca_prefill(self) -> None:
response = self.app.get(self.add_url, user=self.user.username)
form = response.forms["certificate_form"]
- form["csr"] = certs["child-cert"]["csr"]["pem"]
+ form["csr"] = CERT_DATA["child-cert"]["csr"]["pem"]
form["subject_0"] = json.dumps([{"key": NameOID.COMMON_NAME.dotted_string, "value": cn}])
response = form.submit().follow()
self.assertEqual(response.status_code, 200)
@@ -1788,7 +1791,7 @@ def test_full_profile_prefill(self) -> None:
# default value for form field is on import time, so override settings does not change
# profile field
form["profile"] = "everything"
- form["csr"] = certs["child-cert"]["csr"]["pem"]
+ form["csr"] = CERT_DATA["child-cert"]["csr"]["pem"]
form["subject_0"] = json.dumps([{"key": NameOID.COMMON_NAME.dotted_string, "value": cn}])
response = form.submit().follow()
self.assertEqual(response.status_code, 200)
@@ -1901,7 +1904,7 @@ def test_multiple_distribution_points(self) -> None:
# default value for form field is on import time, so override settings does not change
# profile field
form["profile"] = "everything"
- form["csr"] = certs["child-cert"]["csr"]["pem"]
+ form["csr"] = CERT_DATA["child-cert"]["csr"]["pem"]
form["subject_0"] = json.dumps([{"key": NameOID.COMMON_NAME.dotted_string, "value": cn}])
response = form.submit()
response = response.follow()
diff --git a/ca/django_ca/tests/admin/test_extra_views.py b/ca/django_ca/tests/admin/test_extra_views.py
index cae1d8ad3..b65e50568 100644
--- a/ca/django_ca/tests/admin/test_extra_views.py
+++ b/ca/django_ca/tests/admin/test_extra_views.py
@@ -34,7 +34,8 @@
from django_ca import ca_settings, constants
from django_ca.models import CertificateAuthority
from django_ca.tests.admin.base import CertificateModelAdminTestCaseMixin
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
+from django_ca.tests.base.utils import override_tmpcadir
from django_ca.utils import serialize_name, x509_name
@@ -42,7 +43,7 @@ class CSRDetailTestCase(CertificateModelAdminTestCaseMixin, TestCase):
"""Test the CSR detail view."""
url = reverse("admin:django_ca_certificate_csr_details")
- csr_pem = certs["root-cert"]["csr"]["pem"]
+ csr_pem = CERT_DATA["root-cert"]["csr"]["pem"]
@classmethod
def create_csr(
@@ -60,7 +61,7 @@ def create_csr(
def test_basic(self) -> None:
"""Test a basic CSR info retrieval."""
- for cert_data in [v for v in certs.values() if v["type"] == "cert" and v["cat"] == "generated"]:
+ for cert_data in [v for v in CERT_DATA.values() if v["type"] == "cert" and v["cat"] == "generated"]:
response = self.client.post(
self.url, data=json.dumps({"csr": cert_data["csr"]["pem"]}), content_type="application/json"
)
@@ -163,7 +164,7 @@ class CADetailsViewTestCase(CertificateModelAdminTestCaseMixin, TestCase):
url = reverse("admin:django_ca_certificate_ca_details")
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_basic(self) -> None:
"""Test fetching CA with all kinds of URLs."""
self.ca.issuer_url = "http://issuer.child.example.com"
@@ -224,7 +225,7 @@ def test_basic(self) -> None:
)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_empty_ca(self) -> None:
"""Test fetching CA with no URLs."""
self.ca.issuer_url = ""
diff --git a/ca/django_ca/tests/admin/test_views.py b/ca/django_ca/tests/admin/test_views.py
index 8ef28e3ad..3f6aa2719 100644
--- a/ca/django_ca/tests/admin/test_views.py
+++ b/ca/django_ca/tests/admin/test_views.py
@@ -24,8 +24,8 @@
from django_ca.constants import ReasonFlags
from django_ca.models import Certificate, Watcher
-from django_ca.tests.base import timestamps
from django_ca.tests.base.assertions import assert_change_response, assert_changelist_response
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
@@ -162,7 +162,7 @@ def test_change_view_with_no_subject_alternative_name(
assertContains(response, text=html, html=True) # type: ignore[arg-type]
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_changelist_autogenerated_filter(admin_client: Client, root_cert: Certificate) -> None:
"""Test :py:class:`~django_ca.admin.AutoGeneratedFilter`."""
response = admin_client.get(Certificate.admin_changelist_url)
@@ -191,7 +191,7 @@ def test_changelist_status_filter(
child_cert.revoke(ReasonFlags.unspecified)
child_cert.save()
- with freeze_time(timestamps["everything_valid"]):
+ with freeze_time(TIMESTAMPS["everything_valid"]):
response = admin_client.get(Certificate.admin_changelist_url)
assert_changelist_response(response, root_cert)
response = admin_client.get(Certificate.admin_changelist_url, {"status": "expired"})
@@ -201,7 +201,7 @@ def test_changelist_status_filter(
response = admin_client.get(Certificate.admin_changelist_url, {"status": "all"})
assert_changelist_response(response, root_cert, child_cert)
- with freeze_time(timestamps["everything_expired"]):
+ with freeze_time(TIMESTAMPS["everything_expired"]):
admin_client.force_login(admin_user)
response = admin_client.get(Certificate.admin_changelist_url)
assert_changelist_response(response)
diff --git a/ca/django_ca/tests/api/test_list_cas.py b/ca/django_ca/tests/api/test_list_cas.py
index 5763626aa..ea81419a8 100644
--- a/ca/django_ca/tests/api/test_list_cas.py
+++ b/ca/django_ca/tests/api/test_list_cas.py
@@ -26,7 +26,7 @@
from django_ca.models import CertificateAuthority
from django_ca.tests.api.conftest import APIPermissionTestBase, ListResponse
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
path = reverse_lazy("django_ca:api:list_certificate_authorities")
@@ -57,7 +57,7 @@ def test_empty_list_view(api_client: Client) -> None:
assert response.json() == []
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_list_view(api_client: Client, expected_response: ListResponse) -> None:
"""Test an ordinary list view."""
response = request(api_client)
@@ -65,7 +65,7 @@ def test_list_view(api_client: Client, expected_response: ListResponse) -> None:
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_certificate_authorities_are_excluded(api_client: Client) -> None:
"""Test that expired CAs are excluded by default."""
response = request(api_client)
@@ -73,7 +73,7 @@ def test_expired_certificate_authorities_are_excluded(api_client: Client) -> Non
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_filter(api_client: Client, expected_response: ListResponse) -> None:
"""Test that expired CAs are excluded by default."""
response = request(api_client, {"expired": "1"})
@@ -81,7 +81,7 @@ def test_expired_filter(api_client: Client, expected_response: ListResponse) ->
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(api_client: Client, root: CertificateAuthority) -> None:
"""Test that a disabled CA is *not* included."""
root.enabled = False
diff --git a/ca/django_ca/tests/api/test_list_certs.py b/ca/django_ca/tests/api/test_list_certs.py
index de9cb8dfc..47a1795e5 100644
--- a/ca/django_ca/tests/api/test_list_certs.py
+++ b/ca/django_ca/tests/api/test_list_certs.py
@@ -27,11 +27,10 @@
from django_ca.models import Certificate
from django_ca.tests.api.conftest import APIPermissionTestBase, ListResponse
-from django_ca.tests.base import timestamps
-from django_ca.tests.base.conftest_helpers import certs
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.utils import iso_format
-path = reverse_lazy("django_ca:api:list_certificates", kwargs={"serial": certs["root"]["serial"]})
+path = reverse_lazy("django_ca:api:list_certificates", kwargs={"serial": CERT_DATA["root"]["serial"]})
@pytest.fixture(scope="module")
@@ -55,7 +54,7 @@ def test_empty_list_view(api_client: Client) -> None:
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_list_view(api_client: Client, expected_response: ListResponse) -> None:
"""Test an ordinary list view."""
response = api_client.get(path)
@@ -64,7 +63,7 @@ def test_list_view(api_client: Client, expected_response: ListResponse) -> None:
@pytest.mark.usefixtures("root_cert")
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_certificates_are_excluded(api_client: Client) -> None:
"""Test that expired certificates are excluded by default."""
response = api_client.get(path)
@@ -72,7 +71,7 @@ def test_expired_certificates_are_excluded(api_client: Client) -> None:
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_autogenerated_are_excluded(api_client: Client, root_cert: Certificate) -> None:
"""Test that auto-generated certificates are excluded by default."""
root_cert.autogenerated = True
@@ -83,7 +82,7 @@ def test_autogenerated_are_excluded(api_client: Client, root_cert: Certificate)
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_revoked_are_excluded(api_client: Client, root_cert: Certificate) -> None:
"""Test that revoked certificates are excluded by default."""
root_cert.revoke()
@@ -93,7 +92,7 @@ def test_revoked_are_excluded(api_client: Client, root_cert: Certificate) -> Non
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_autogenerated_filter(
api_client: Client, root_cert: Certificate, expected_response: ListResponse
) -> None:
@@ -108,7 +107,7 @@ def test_autogenerated_filter(
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_profile_filter(api_client: Client, root_cert: Certificate, expected_response: ListResponse) -> None:
"""Test the `profile` filter."""
root_cert.profile = "webserver"
@@ -126,7 +125,7 @@ def test_profile_filter(api_client: Client, root_cert: Certificate, expected_res
assert response.json() == [], response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_filter(api_client: Client, expected_response: ListResponse) -> None:
"""Test the `expired` filter."""
response = api_client.get(path, {"expired": "1"})
@@ -134,7 +133,7 @@ def test_expired_filter(api_client: Client, expected_response: ListResponse) ->
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_revoked_filter(api_client: Client, root_cert: Certificate, expected_response: ListResponse) -> None:
"""Test the `revoked` filter."""
root_cert.revoke()
@@ -146,7 +145,7 @@ def test_revoked_filter(api_client: Client, root_cert: Certificate, expected_res
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(api_client: Client, root_cert: Certificate) -> None:
"""Test that certificates for a disabled can *not* be viewed."""
root_cert.ca.enabled = False
diff --git a/ca/django_ca/tests/api/test_revoke_cert.py b/ca/django_ca/tests/api/test_revoke_cert.py
index 081ece0af..a90e19c7a 100644
--- a/ca/django_ca/tests/api/test_revoke_cert.py
+++ b/ca/django_ca/tests/api/test_revoke_cert.py
@@ -27,14 +27,13 @@
from django_ca.models import Certificate
from django_ca.tests.api.conftest import APIPermissionTestBase, DetailResponse
-from django_ca.tests.base import timestamps
-from django_ca.tests.base.conftest_helpers import certs
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
from django_ca.tests.base.utils import iso_format
path = reverse_lazy(
"django_ca:api:revoke_certificate",
- kwargs={"serial": certs["root"]["serial"], "certificate_serial": certs["root-cert"]["serial"]},
+ kwargs={"serial": CERT_DATA["root"]["serial"], "certificate_serial": CERT_DATA["root-cert"]["serial"]},
)
@@ -51,7 +50,7 @@ def expected_response(root_cert_response: Dict[str, Any]) -> DetailResponse:
return root_cert_response
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_revoke_view(root_cert: Certificate, api_client: Client, expected_response: DetailResponse) -> None:
"""Test an ordinary certificate revocation."""
response = api_client.post(path, {}, content_type="application/json")
@@ -64,7 +63,7 @@ def test_revoke_view(root_cert: Certificate, api_client: Client, expected_respon
assert root_cert.compromised is None
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_revoke_with_parameters(
root_cert: Certificate, api_client: Client, expected_response: DetailResponse
) -> None:
@@ -87,7 +86,7 @@ def test_revoke_with_parameters(
assert root_cert.compromised == now
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_revoked_certificate_fails(root_cert: Certificate, api_client: Client) -> None:
"""Test that revoking a revoked certificate fails."""
root_cert.revoke()
@@ -97,7 +96,7 @@ def test_revoked_certificate_fails(root_cert: Certificate, api_client: Client) -
assert response.json() == {"detail": "The certificate is already revoked."}, response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_cannot_revoke_expired_certificate(root_cert: Certificate, api_client: Client) -> None:
"""Test that we cannot revoke a certificate if it is expired."""
response = api_client.post(path, {}, content_type="application/json")
@@ -108,7 +107,7 @@ def test_cannot_revoke_expired_certificate(root_cert: Certificate, api_client: C
assert root_cert.revoked is False # cert is still not revoked (just expired)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
@pytest.mark.usefixtures("root") # CA should exist, but certificate does not
def test_certificate_not_found(api_client: Client) -> None:
"""Test response when a certificate was not found."""
@@ -117,7 +116,7 @@ def test_certificate_not_found(api_client: Client) -> None:
assert response.json() == {"detail": "Not Found"}, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(root_cert: Certificate, api_client: Client) -> None:
"""Test that certificates for a disabled can *not* be viewed."""
root_cert.ca.enabled = False
diff --git a/ca/django_ca/tests/api/test_sign_cert.py b/ca/django_ca/tests/api/test_sign_cert.py
index 568f8039e..57cf06496 100644
--- a/ca/django_ca/tests/api/test_sign_cert.py
+++ b/ca/django_ca/tests/api/test_sign_cert.py
@@ -35,24 +35,27 @@
from django_ca import ca_settings, constants
from django_ca.models import Certificate, CertificateAuthority
from django_ca.tests.api.conftest import APIPermissionTestBase
-from django_ca.tests.base import dns, ip, rdn, timestamps, uri
-from django_ca.tests.base.conftest_helpers import certs
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
from django_ca.tests.base.utils import (
authority_information_access,
certificate_policies,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
freshest_crl,
+ ip,
iso_format,
key_usage,
ocsp_no_check,
+ rdn,
subject_alternative_name,
tls_feature,
+ uri,
)
-path = reverse_lazy("django_ca:api:sign_certificate", kwargs={"serial": certs["root"]["serial"]})
+path = reverse_lazy("django_ca:api:sign_certificate", kwargs={"serial": CERT_DATA["root"]["serial"]})
default_subject = [{"oid": NameOID.COMMON_NAME.dotted_string, "value": "api.example.com"}]
@@ -67,14 +70,14 @@ def expected_response(root: CertificateAuthority) -> Dict[str, Any]:
"""Fixture for the non-dynamic parts of the expected response."""
return {
"autogenerated": False,
- "created": iso_format(timestamps["everything_valid"]),
+ "created": iso_format(TIMESTAMPS["everything_valid"]),
"issuer": [{"oid": attr.oid.dotted_string, "value": attr.value} for attr in root.issuer],
- "not_after": iso_format(timestamps["everything_valid"] + ca_settings.CA_DEFAULT_EXPIRES),
- "not_before": iso_format(timestamps["everything_valid"]),
+ "not_after": iso_format(TIMESTAMPS["everything_valid"] + ca_settings.CA_DEFAULT_EXPIRES),
+ "not_before": iso_format(TIMESTAMPS["everything_valid"]),
"profile": ca_settings.CA_DEFAULT_PROFILE,
"revoked": False,
"subject": default_subject,
- "updated": iso_format(timestamps["everything_valid"]),
+ "updated": iso_format(TIMESTAMPS["everything_valid"]),
}
@@ -83,12 +86,12 @@ def request(client: Client, data: Dict[str, Any]) -> HttpResponse:
return client.post(path, data, content_type="application/json")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_sign_ca_values(
api_client: Client, usable_root: CertificateAuthority, expected_response: Dict[str, Any]
) -> None:
"""Test that CA extensions are added."""
- response = request(api_client, {"csr": certs["root-cert"]["csr"]["pem"], "subject": default_subject})
+ response = request(api_client, {"csr": CERT_DATA["root-cert"]["csr"]["pem"], "subject": default_subject})
assert response.status_code == HTTPStatus.OK, response.content
# Get certificate and validate some properties
@@ -115,7 +118,7 @@ def test_sign_ca_values(
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_sign_certificate_with_parameters(
api_client: Client,
usable_root: CertificateAuthority,
@@ -129,7 +132,7 @@ def test_sign_certificate_with_parameters(
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"autogenerated": True,
"profile": "server",
@@ -152,7 +155,7 @@ def test_sign_certificate_with_parameters(
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_sign_certificate_with_extensions(
api_client: Client, usable_root: CertificateAuthority, expected_response: Dict[str, Any]
) -> None:
@@ -160,7 +163,7 @@ def test_sign_certificate_with_extensions(
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"extensions": {
"authority_information_access": {
@@ -283,7 +286,7 @@ def test_sign_certificate_with_extensions(
assert exts[ExtensionOID.TLS_FEATURE] == tls_feature(x509.TLSFeatureType.status_request)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_sign_certificate_with_subject_alternative_name(
api_client: Client, usable_root: CertificateAuthority, expected_response: Dict[str, Any]
) -> None:
@@ -291,7 +294,7 @@ def test_sign_certificate_with_subject_alternative_name(
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"extensions": {
"subject_alternative_name": {
@@ -324,13 +327,13 @@ def test_sign_certificate_with_subject_alternative_name(
@pytest.mark.usefixtures("tmpcadir")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_crldp_with_full_name_and_relative_name(api_client: Client) -> None:
"""Test sending a CRL Distribution point with a full_name and a relative_name."""
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"extensions": {
"crl_distribution_points": {
@@ -365,13 +368,13 @@ def test_crldp_with_full_name_and_relative_name(api_client: Client) -> None:
@pytest.mark.usefixtures("tmpcadir")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_crldp_with_no_full_name_or_relative_name(api_client: Client) -> None:
"""Test sending a CRL Distribution point with neither a full name nor a relative name."""
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"extensions": {
"crl_distribution_points": {
@@ -403,13 +406,13 @@ def test_crldp_with_no_full_name_or_relative_name(api_client: Client) -> None:
@pytest.mark.usefixtures("tmpcadir")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_with_invalid_key_usage(api_client: Client) -> None:
"""Test sending an invalid key usage."""
response = request(
api_client,
{
- "csr": certs["root-cert"]["csr"]["pem"],
+ "csr": CERT_DATA["root-cert"]["csr"]["pem"],
"subject": default_subject,
"extensions": {"key_usage": {"value": ["unknown"]}},
},
@@ -427,19 +430,19 @@ def test_with_invalid_key_usage(api_client: Client) -> None:
@pytest.mark.usefixtures("tmpcadir", "usable_root")
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_ca(api_client: Client) -> None:
"""Test that you can *not* sign a certificate for an expired CA."""
- response = request(api_client, {"csr": certs["root-cert"]["csr"]["pem"], "subject": default_subject})
+ response = request(api_client, {"csr": CERT_DATA["root-cert"]["csr"]["pem"], "subject": default_subject})
assert response.status_code == HTTPStatus.NOT_FOUND, response.content
assert response.json() == {"detail": "Not Found"}, response.json()
@pytest.mark.usefixtures("root")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_private_key_unavailable(api_client: Client) -> None:
"""Test the error when no private key is available."""
- response = request(api_client, {"csr": certs["root-cert"]["csr"]["pem"], "subject": default_subject})
+ response = request(api_client, {"csr": CERT_DATA["root-cert"]["csr"]["pem"], "subject": default_subject})
assert response.status_code == HTTPStatus.BAD_REQUEST, response.content
assert response.json() == {
"detail": "This certificate authority can not be used to sign certificates via the API."
@@ -447,13 +450,13 @@ def test_private_key_unavailable(api_client: Client) -> None:
@pytest.mark.usefixtures("tmpcadir")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(api_client: Client, root: CertificateAuthority) -> None:
"""Test that you cannot sign a certificate for a disabled CA."""
root.enabled = False
root.save()
- response = request(api_client, {"csr": certs["root-cert"]["csr"]["pem"], "subject": default_subject})
+ response = request(api_client, {"csr": CERT_DATA["root-cert"]["csr"]["pem"], "subject": default_subject})
assert response.status_code == HTTPStatus.NOT_FOUND, response.content
assert response.json() == {"detail": "Not Found"}, response.json()
@@ -464,4 +467,4 @@ class TestPermissions(APIPermissionTestBase):
path = path
def request(self, client: Client) -> HttpResponse:
- return request(client, {"csr": certs["root-cert"]["csr"]["pem"], "subject": default_subject})
+ return request(client, {"csr": CERT_DATA["root-cert"]["csr"]["pem"], "subject": default_subject})
diff --git a/ca/django_ca/tests/api/test_update_ca.py b/ca/django_ca/tests/api/test_update_ca.py
index 09cba0017..b2d6a0772 100644
--- a/ca/django_ca/tests/api/test_update_ca.py
+++ b/ca/django_ca/tests/api/test_update_ca.py
@@ -30,13 +30,14 @@
from django_ca import constants
from django_ca.models import CertificateAuthority
from django_ca.tests.api.conftest import APIPermissionTestBase
-from django_ca.tests.base import timestamps
-from django_ca.tests.base.conftest_helpers import certs
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
from django_ca.tests.base.utils import certificate_policies, iso_format
from django_ca.typehints import JSON
-path = reverse_lazy("django_ca:api:update_certificate_authority", kwargs={"serial": certs["root"]["serial"]})
+path = reverse_lazy(
+ "django_ca:api:update_certificate_authority", kwargs={"serial": CERT_DATA["root"]["serial"]}
+)
def request(client: Client, payload: Optional[Dict[str, JSON]]) -> "HttpResponse":
@@ -83,20 +84,20 @@ def expected_response(root: CertificateAuthority, payload: Dict[str, Any]) -> Di
"issuer": [{"oid": attr.oid.dotted_string, "value": attr.value} for attr in root.issuer],
"not_after": iso_format(root.expires),
"not_before": iso_format(root.valid_from),
- "pem": certs["root"]["pub"]["pem"],
+ "pem": CERT_DATA["root"]["pub"]["pem"],
"revoked": False,
- "serial": certs["root"]["serial"],
+ "serial": CERT_DATA["root"]["serial"],
"sign_certificate_policies": {
"critical": constants.EXTENSION_DEFAULT_CRITICAL[ExtensionOID.CERTIFICATE_POLICIES],
"value": [{"policy_identifier": "1.1.1", "policy_qualifiers": None}],
},
"subject": [{"oid": attr.oid.dotted_string, "value": attr.value} for attr in root.subject],
- "updated": iso_format(timestamps["everything_valid"]),
+ "updated": iso_format(TIMESTAMPS["everything_valid"]),
},
)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_update(
root: CertificateAuthority, api_client: Client, payload: Dict[str, Any], expected_response: Dict[str, Any]
) -> None:
@@ -126,7 +127,7 @@ def test_update(
assert expected == actual
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_minimal_update(
root: CertificateAuthority, api_client: Client, payload: Dict[str, Any], expected_response: Dict[str, Any]
) -> None:
@@ -146,7 +147,7 @@ def test_minimal_update(
assert root.ocsp_responder_key_validity == 10
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_validation(
root: CertificateAuthority, api_client: Client, payload: Dict[str, Any], expected_response: Dict[str, Any]
) -> None:
@@ -166,18 +167,18 @@ def test_validation(
assert root.ocsp_responder_key_validity == refetched_root.ocsp_responder_key_validity
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_update_expired_ca(
api_client: Client, payload: Dict[str, Any], expected_response: Dict[str, Any]
) -> None:
"""Test that we can update an expired CA."""
- expected_response["updated"] = iso_format(timestamps["everything_expired"])
+ expected_response["updated"] = iso_format(TIMESTAMPS["everything_expired"])
response = request(api_client, payload)
assert response.status_code == HTTPStatus.OK, response.content
assert response.json() == expected_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(root: CertificateAuthority, api_client: Client, payload: Dict[str, Any]) -> None:
"""Test that a disabled CA is *not* updatable."""
root.enabled = False
diff --git a/ca/django_ca/tests/api/test_view_ca.py b/ca/django_ca/tests/api/test_view_ca.py
index 8ede20e74..aa26a2e3e 100644
--- a/ca/django_ca/tests/api/test_view_ca.py
+++ b/ca/django_ca/tests/api/test_view_ca.py
@@ -24,10 +24,11 @@
from django_ca.models import CertificateAuthority
from django_ca.tests.api.conftest import APIPermissionTestBase
-from django_ca.tests.base import timestamps
-from django_ca.tests.base.conftest_helpers import certs
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
-path = reverse_lazy("django_ca:api:view_certificate_authority", kwargs={"serial": certs["root"]["serial"]})
+path = reverse_lazy(
+ "django_ca:api:view_certificate_authority", kwargs={"serial": CERT_DATA["root"]["serial"]}
+)
@pytest.fixture(scope="module")
@@ -36,7 +37,7 @@ def api_permission() -> Tuple[Type[Model], str]:
return CertificateAuthority, "view_certificateauthority"
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_view(api_client: Client, root_response: Dict[str, Any]) -> None:
"""Test an ordinary view."""
response = api_client.get(path)
@@ -44,7 +45,7 @@ def test_view(api_client: Client, root_response: Dict[str, Any]) -> None:
assert response.json() == root_response, response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_view_expired_ca(api_client: Client, root_response: Dict[str, Any]) -> None:
"""Test that we can view an expired CA."""
response = api_client.get(path)
@@ -52,7 +53,7 @@ def test_view_expired_ca(api_client: Client, root_response: Dict[str, Any]) -> N
assert response.json() == root_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(root: CertificateAuthority, api_client: Client) -> None:
"""Test that a disabled CA is *not* viewable."""
root.enabled = False
diff --git a/ca/django_ca/tests/api/test_view_cert.py b/ca/django_ca/tests/api/test_view_cert.py
index 5856ccd75..b5a7aea8a 100644
--- a/ca/django_ca/tests/api/test_view_cert.py
+++ b/ca/django_ca/tests/api/test_view_cert.py
@@ -24,11 +24,11 @@
from django_ca.models import Certificate, CertificateAuthority
from django_ca.tests.api.conftest import APIPermissionTestBase
-from django_ca.tests.base import certs, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
path = reverse_lazy(
"django_ca:api:view_certificate",
- kwargs={"serial": certs["root"]["serial"], "certificate_serial": certs["root-cert"]["serial"]},
+ kwargs={"serial": CERT_DATA["root"]["serial"], "certificate_serial": CERT_DATA["root-cert"]["serial"]},
)
@@ -38,7 +38,7 @@ def api_permission() -> Tuple[Type[Model], str]:
return Certificate, "view_certificate"
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_detail_view(api_client: Client, root_cert_response: Dict[str, Any]) -> None:
"""Test an ordinary detail view."""
response = api_client.get(path)
@@ -46,7 +46,7 @@ def test_detail_view(api_client: Client, root_cert_response: Dict[str, Any]) ->
assert response.json() == root_cert_response, response.json()
-@freeze_time(timestamps["everything_expired"])
+@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_certificate(api_client: Client, root_cert_response: Dict[str, Any]) -> None:
"""Test that we can view the certificate even if it is expired."""
response = api_client.get(path)
@@ -54,7 +54,7 @@ def test_expired_certificate(api_client: Client, root_cert_response: Dict[str, A
assert response.json() == root_cert_response, response.json()
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
def test_disabled_ca(root: CertificateAuthority, api_client: Client) -> None:
"""Test that certificates for a disabled can *not* be viewed."""
root.enabled = False
diff --git a/ca/django_ca/tests/base/__init__.py b/ca/django_ca/tests/base/__init__.py
index 6600d3f93..08bd6d714 100644
--- a/ca/django_ca/tests/base/__init__.py
+++ b/ca/django_ca/tests/base/__init__.py
@@ -12,457 +12,3 @@
# .
"""TestCase base classes that preload some data and add common helper methods."""
-
-import inspect
-import ipaddress
-import json
-import os
-import re
-import shutil
-import tempfile
-import typing
-from contextlib import contextmanager
-from datetime import datetime, timedelta, timezone as tz
-from typing import Any, Dict, Iterable, Iterator, Tuple, Union
-from unittest.mock import patch
-
-import cryptography
-from cryptography import x509
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.asymmetric.types import CertificateIssuerPrivateKeyTypes
-
-from django.conf import settings
-from django.test.utils import override_settings
-from django.utils import timezone
-
-from django_ca.constants import EXTENSION_KEY_OIDS
-from django_ca.extensions import parse_extension
-from django_ca.profiles import profiles
-from django_ca.tests.base.constants import (
- CRYPTOGRAPHY_VERSION,
- DOC_DIR,
- FIXTURES_DIR,
- GECKODRIVER_PATH,
- RUN_SELENIUM_TESTS,
-)
-from django_ca.utils import add_colons, ca_storage, format_name
-
-FuncTypeVar = typing.TypeVar("FuncTypeVar", bound=typing.Callable[..., Any])
-KeyDict = typing.TypedDict("KeyDict", {"pem": str, "parsed": CertificateIssuerPrivateKeyTypes})
-CsrDict = typing.TypedDict("CsrDict", {"pem": str, "parsed": x509.CertificateSigningRequest})
-_PubDict = typing.TypedDict("_PubDict", {"pem": str, "parsed": x509.Certificate})
-
-
-# Regex used by certbot to split PEM-encoded certificate chains/bundles as of 2022-01-23. See also:
-# https://github.com/certbot/certbot/blob/master/certbot/certbot/crypto_util.py
-CERT_PEM_REGEX = re.compile(
- b"""-----BEGIN CERTIFICATE-----\r?
-.+?\r?
------END CERTIFICATE-----\r?
-""",
- re.DOTALL, # DOTALL (/s) because the base64text may include newlines
-)
-
-
-# pylint: disable-next=inherit-non-class; False positive
-class PubDict(_PubDict, total=False):
- """TypedDict for the pub key of certs."""
-
- der: bytes
-
-
-def _load_key(data: Dict[Any, Any]) -> KeyDict:
- with open(os.path.join(FIXTURES_DIR, data["key_filename"]), "rb") as stream:
- raw = stream.read()
-
- parsed = serialization.load_pem_private_key(
- raw, password=data.get("password"), unsafe_skip_rsa_key_validation=True
- )
-
- return {
- "pem": raw.decode("utf-8"),
- "parsed": parsed, # type: ignore[typeddict-item] # we do not support all key types
- }
-
-
-def _load_csr(data: Dict[Any, Any]) -> CsrDict:
- with open(os.path.join(FIXTURES_DIR, data["csr_filename"]), "rb") as stream:
- raw = stream.read()
-
- parsed = x509.load_pem_x509_csr(raw)
- return {
- "pem": raw.decode("utf-8"),
- "parsed": parsed,
- }
-
-
-def _load_pub(data: Dict[Any, Any]) -> PubDict:
- # basedir is set for certificates in docs/source/_files
- basedir = data.get("basedir", FIXTURES_DIR)
- path = os.path.join(basedir, data["pub_filename"])
-
- with open(path, "rb") as stream:
- pem = stream.read()
-
- pub_data: PubDict = {
- "pem": pem.decode("utf-8"),
- "parsed": x509.load_pem_x509_certificate(pem),
- }
-
- if der_filename := data.get("pub_der_filename"):
- with open(os.path.join(basedir, der_filename), "rb") as stream:
- der = stream.read()
- pub_data["der"] = der
-
- return pub_data
-
-
-cryptography_version = tuple(int(t) for t in cryptography.__version__.split(".")[:2])
-
-with open(os.path.join(FIXTURES_DIR, "cert-data.json"), encoding="utf-8") as cert_data_stream:
- _fixture_data = json.load(cert_data_stream)
-certs = _fixture_data.get("certs")
-
-# Update some data from contrib (data is not in cert-data.json, since we don't generate them)
-certs["multiple_ous"] = {
- "name": "multiple_ous",
- "subject": [
- ["C", "US"],
- ["O", "VeriSign, Inc."],
- ["OU", "Class 3 Public Primary Certification Authority - G2"],
- ["OU", "(c) 1998 VeriSign, Inc. - For authorized use only"],
- ["OU", "VeriSign Trust Network"],
- ],
- "subject_str": "/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network", # noqa: E501
- "cn": "",
- "key_filename": False,
- "csr_filename": False,
- "pub_filename": os.path.join("contrib", "multiple_ous_and_no_ext.pem"),
- "key_type": "RSA",
- "cat": "contrib",
- "type": "cert",
- "valid_from": "1998-05-18 00:00:00",
- "valid_until": "2028-08-01 23:59:59",
- "ca": "root",
- "serial": "7DD9FE07CFA81EB7107967FBA78934C6",
- "md5": "A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9",
- "sha1": "85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F",
- "sha256": "83:CE:3C:12:29:68:8A:59:3D:48:5F:81:97:3C:0F:91:95:43:1E:DA:37:CC:5E:36:43:0E:79:C7:A8:88:63:8B", # noqa: E501
- "sha512": "86:20:07:9F:8B:06:80:43:44:98:F6:7A:A4:22:DE:7E:2B:33:10:9B:65:72:79:C4:EB:F3:F3:0F:66:C8:6E:89:1D:4C:6C:09:1C:83:45:D1:25:6C:F8:65:EB:9A:B9:50:8F:26:A8:85:AE:3A:E4:8A:58:60:48:65:BB:44:B6:CE", # NOQA
-}
-certs["cloudflare_1"] = {
- "name": "cloudflare_1",
- "subject": [
- ["OU", "Domain Control Validated"],
- ["OU", "PositiveSSL Multi-Domain"],
- ["CN", "sni24142.cloudflaressl.com"],
- ],
- "subject_str": "/OU=Domain Control Validated/OU=PositiveSSL Multi-Domain/CN=sni24142.cloudflaressl.com",
- "cn": "sni24142.cloudflaressl.com",
- "key_filename": False,
- "csr_filename": False,
- "pub_filename": os.path.join("contrib", "cloudflare_1.pem"),
- "cat": "contrib",
- "type": "cert",
- "key_type": "EC",
- "valid_from": "2018-07-18 00:00:00",
- "valid_until": "2019-01-24 23:59:59",
- "ca": "root",
- "serial": "92529ABD85F0A6A4D6C53FD1C91011C1",
- "md5": "D6:76:03:E9:4F:3B:B0:F1:F7:E3:A1:40:80:8E:F0:4A",
- "sha1": "71:BD:B8:21:80:BD:86:E8:E5:F4:2B:6D:96:82:B2:EF:19:53:ED:D3",
- "sha256": "1D:8E:D5:41:E5:FF:19:70:6F:65:86:A9:A3:6F:DF:DE:F8:A0:07:22:92:71:9E:F1:CD:F8:28:37:39:02:E0:A1", # NOQA
- "sha512": "FF:03:1B:8F:11:E8:A7:FF:91:4F:B9:97:E9:97:BC:77:37:C1:A7:69:86:F3:7C:E3:BB:BB:DF:A6:4F:0E:3C:C0:7F:B5:BC:CC:BD:0A:D5:EF:5F:94:55:E9:FF:48:41:34:B8:11:54:57:DD:90:85:41:2E:71:70:5E:FA:BA:E6:EA", # NOQA
- "authority_information_access": {
- "critical": False,
- "value": {
- "issuers": ["URI:http://crt.comodoca4.com/COMODOECCDomainValidationSecureServerCA2.crt"],
- "ocsp": ["URI:http://ocsp.comodoca4.com"],
- },
- },
- "authority_key_identifier": {
- "critical": False,
- "value": "40:09:61:67:F0:BC:83:71:4F:DE:12:08:2C:6F:D4:D4:2B:76:3D:96",
- },
- "basic_constraints": {
- "critical": True,
- "value": {"ca": False},
- },
- "crl_distribution_points": {
- "value": [
- {
- "full_name": [
- "URI:http://crl.comodoca4.com/COMODOECCDomainValidationSecureServerCA2.crl",
- ],
- }
- ],
- "critical": False,
- },
- "extended_key_usage": {
- "critical": False,
- "value": ["serverAuth", "clientAuth"],
- },
- "key_usage": {
- "critical": True,
- "value": ["digital_signature"],
- },
- "precert_poison": {"critical": True},
- "subject_alternative_name": {
- "value": [
- "DNS:sni24142.cloudflaressl.com",
- "DNS:*.animereborn.com",
- "DNS:*.beglideas.ga",
- "DNS:*.chroma.ink",
- "DNS:*.chuckscleanings.ga",
- "DNS:*.clipvuigiaitris.ga",
- "DNS:*.cmvsjns.ga",
- "DNS:*.competegraphs.ga",
- "DNS:*.consoleprints.ga",
- "DNS:*.copybreezes.ga",
- "DNS:*.corphreyeds.ga",
- "DNS:*.cyanigees.ga",
- "DNS:*.dadpbears.ga",
- "DNS:*.dahuleworldwides.ga",
- "DNS:*.dailyopeningss.ga",
- "DNS:*.daleylexs.ga",
- "DNS:*.danajweinkles.ga",
- "DNS:*.dancewthyogas.ga",
- "DNS:*.darkmoosevpss.ga",
- "DNS:*.daurat.com.ar",
- "DNS:*.deltaberg.com",
- "DNS:*.drjahanobgyns.ga",
- "DNS:*.drunkgirliess.ga",
- "DNS:*.duhiepkys.ga",
- "DNS:*.dujuanjsqs.ga",
- "DNS:*.dumbiseasys.ga",
- "DNS:*.dumpsoftdrinkss.ga",
- "DNS:*.dunhavenwoodss.ga",
- "DNS:*.durabiliteas.ga",
- "DNS:*.duxmangroups.ga",
- "DNS:*.dvpdrivewayss.ga",
- "DNS:*.dwellwizes.ga",
- "DNS:*.dwwkouis.ga",
- "DNS:*.entertastic.com",
- "DNS:*.estudiogolber.com.ar",
- "DNS:*.letsretro.team",
- "DNS:*.maccuish.org.uk",
- "DNS:*.madamsquiggles.com",
- "DNS:*.sftw.ninja",
- "DNS:*.spangenberg.io",
- "DNS:*.timmutton.com.au",
- "DNS:*.wyomingsexbook.com",
- "DNS:*.ych.bid",
- "DNS:animereborn.com",
- "DNS:beglideas.ga",
- "DNS:chroma.ink",
- "DNS:chuckscleanings.ga",
- "DNS:clipvuigiaitris.ga",
- "DNS:cmvsjns.ga",
- "DNS:competegraphs.ga",
- "DNS:consoleprints.ga",
- "DNS:copybreezes.ga",
- "DNS:corphreyeds.ga",
- "DNS:cyanigees.ga",
- "DNS:dadpbears.ga",
- "DNS:dahuleworldwides.ga",
- "DNS:dailyopeningss.ga",
- "DNS:daleylexs.ga",
- "DNS:danajweinkles.ga",
- "DNS:dancewthyogas.ga",
- "DNS:darkmoosevpss.ga",
- "DNS:daurat.com.ar",
- "DNS:deltaberg.com",
- "DNS:drjahanobgyns.ga",
- "DNS:drunkgirliess.ga",
- "DNS:duhiepkys.ga",
- "DNS:dujuanjsqs.ga",
- "DNS:dumbiseasys.ga",
- "DNS:dumpsoftdrinkss.ga",
- "DNS:dunhavenwoodss.ga",
- "DNS:durabiliteas.ga",
- "DNS:duxmangroups.ga",
- "DNS:dvpdrivewayss.ga",
- "DNS:dwellwizes.ga",
- "DNS:dwwkouis.ga",
- "DNS:entertastic.com",
- "DNS:estudiogolber.com.ar",
- "DNS:letsretro.team",
- "DNS:maccuish.org.uk",
- "DNS:madamsquiggles.com",
- "DNS:sftw.ninja",
- "DNS:spangenberg.io",
- "DNS:timmutton.com.au",
- "DNS:wyomingsexbook.com",
- "DNS:ych.bid",
- ]
- },
- "subject_key_identifier": {
- "critical": False,
- "value": "05:86:D8:B4:ED:A9:7E:23:EE:2E:E7:75:AA:3B:2C:06:08:2A:93:B2",
- },
- "certificate_policies": {
- "value": [
- {
- "policy_identifier": "1.3.6.1.4.1.6449.1.2.2.7",
- "policy_qualifiers": ["https://secure.comodo.com/CPS"],
- },
- {"policy_identifier": "2.23.140.1.2.1"},
- ],
- "critical": False,
- },
-}
-
-SPHINX_FIXTURES_DIR = os.path.join(os.path.dirname(settings.BASE_DIR), "docs", "source", "_files")
-for cert_name, cert_data in certs.items():
- cert_data["serial_colons"] = add_colons(cert_data["serial"])
- if cert_data.get("password"):
- cert_data["password"] = cert_data["password"].encode("utf-8")
- if cert_data["cat"] == "sphinx-contrib":
- cert_data["basedir"] = os.path.join(SPHINX_FIXTURES_DIR, cert_data["type"])
-
- if cert_data["type"] == "ca":
- cert_data.setdefault("children", [])
- cert_data["children"] = [(k, add_colons(v)) for k, v in cert_data["children"]]
-
- # Load data from files
- if cert_data["key_filename"] is not False:
- cert_data["key"] = _load_key(cert_data)
- if cert_data["csr_filename"] is not False:
- cert_data["csr"] = _load_csr(cert_data)
- cert_data["pub"] = _load_pub(cert_data)
- cert_data["issuer"] = cert_data["pub"]["parsed"].issuer
- cert_data["issuer_str"] = format_name(cert_data["issuer"])
-
- if "subject" not in cert_data: # pragma: no cover
- raise ValueError(f"subject not in {cert_name}")
- if "subject_str" not in cert_data: # pragma: no cover
- raise ValueError(f"subject_str not in {cert_name}")
- if not isinstance(cert_data["subject"], list): # pragma: no cover
- raise ValueError(cert_data["subject"])
- if not isinstance(cert_data["subject_str"], str): # pragma: no cover
- raise ValueError(cert_data["subject_str"])
-
- # parse some data from the dict
- cert_data["valid_from"] = datetime.strptime(cert_data["valid_from"], "%Y-%m-%d %H:%M:%S")
- cert_data["valid_until"] = datetime.strptime(cert_data["valid_until"], "%Y-%m-%d %H:%M:%S")
- cert_data["valid_from_str"] = cert_data["valid_from"].replace(tzinfo=tz.utc).isoformat(" ")
- cert_data["valid_until_str"] = cert_data["valid_until"].replace(tzinfo=tz.utc).isoformat(" ")
-
- # parse extensions
- for ext_key in EXTENSION_KEY_OIDS:
- if cert_data.get(ext_key):
- cert_data[f"{ext_key}_serialized"] = cert_data[ext_key]
-
- # extensions are not parsable, see also: https://github.com/pyca/cryptography/issues/7824
- if ext_key not in (
- "precertificate_signed_certificate_timestamps",
- "signed_certificate_timestamps",
- ):
- cert_data[ext_key] = parse_extension(ext_key, cert_data[ext_key])
-
-# Calculate some fixed timestamps that we reuse throughout the tests
-timestamps = {
- "base": datetime.fromisoformat(_fixture_data["timestamp"]),
- "before_everything": datetime(1990, 1, 1, tzinfo=tz.utc),
-}
-timestamps["before_cas"] = timestamps["base"] - timedelta(days=1)
-timestamps["before_child"] = timestamps["base"] + timedelta(days=1)
-timestamps["after_child"] = timestamps["base"] + timedelta(days=4)
-timestamps["ca_certs_valid"] = timestamps["base"] + timedelta(days=7)
-timestamps["profile_certs_valid"] = timestamps["base"] + timedelta(days=12)
-
-# When creating fixtures, latest valid_from of any generated cert is 20 days, we need to be after that
-timestamps["everything_valid"] = timestamps["base"] + timedelta(days=23)
-timestamps["everything_valid_naive"] = timezone.make_naive(timestamps["everything_valid"])
-timestamps["cas_expired"] = timestamps["base"] + timedelta(days=731, seconds=3600)
-timestamps["ca_certs_expiring"] = certs["root-cert"]["valid_until"] - timedelta(days=3)
-timestamps["ca_certs_expired"] = certs["root-cert"]["valid_until"] + timedelta(seconds=3600)
-timestamps["profile_certs_expired"] = certs["profile-server"]["valid_until"] + timedelta(seconds=3600)
-timestamps["everything_expired"] = timestamps["base"] + timedelta(days=365 * 20)
-ocsp_data = _fixture_data["ocsp"]
-
-
-def dns(name: str) -> x509.DNSName: # just a shortcut
- """Shortcut to get a :py:class:`cg:cryptography.x509.DNSName`."""
- return x509.DNSName(name)
-
-
-def uri(url: str) -> x509.UniformResourceIdentifier: # just a shortcut
- """Shortcut to get a :py:class:`cg:cryptography.x509.UniformResourceIdentifier`."""
- return x509.UniformResourceIdentifier(url)
-
-
-def ip( # pylint: disable=invalid-name # just a shortcut
- name: Union[ipaddress.IPv4Address, ipaddress.IPv6Address, ipaddress.IPv4Network, ipaddress.IPv6Network]
-) -> x509.IPAddress:
- """Shortcut to get a :py:class:`cg:cryptography.x509.IPAddress`."""
- return x509.IPAddress(name)
-
-
-def rdn(
- name: Iterable[Tuple[x509.ObjectIdentifier, str]]
-) -> x509.RelativeDistinguishedName: # just a shortcut
- """Shortcut to get a :py:class:`cg:cryptography.x509.RelativeDistinguishedName`."""
- return x509.RelativeDistinguishedName([x509.NameAttribute(*t) for t in name])
-
-
-@contextmanager
-def mock_cadir(path: str) -> Iterator[None]:
- """Contextmanager to set the CA_DIR to a given path without actually creating it."""
- with override_settings(CA_DIR=path), patch.object(ca_storage, "location", path), patch.object(
- ca_storage, "_location", path
- ):
- yield
-
-
-class override_tmpcadir(override_settings): # pylint: disable=invalid-name; in line with parent class
- """Sets the CA_DIR directory to a temporary directory.
-
- .. NOTE: This also takes any additional settings.
- """
-
- def __call__(self, test_func: FuncTypeVar) -> FuncTypeVar:
- if not inspect.isfunction(test_func):
- raise ValueError("Only functions can use override_tmpcadir()")
- return super().__call__(test_func) # type: ignore[return-value] # cannot figure out whats right here
-
- def enable(self) -> None:
- self.options["CA_DIR"] = tempfile.mkdtemp()
-
- # copy CAs
- for filename in [v["key_filename"] for v in certs.values() if v["key_filename"] is not False]:
- shutil.copy(os.path.join(FIXTURES_DIR, filename), self.options["CA_DIR"])
-
- # Copy OCSP public key (required for OCSP tests)
- shutil.copy(os.path.join(FIXTURES_DIR, certs["profile-ocsp"]["pub_filename"]), self.options["CA_DIR"])
-
- # pylint: disable=attribute-defined-outside-init
- self.mock = patch.object(ca_storage, "location", self.options["CA_DIR"])
- self.mock_ = patch.object(ca_storage, "_location", self.options["CA_DIR"])
- # pylint: enable=attribute-defined-outside-init
-
- # Reset profiles, so that they are loaded again on first access
- profiles._reset() # pylint: disable=protected-access
-
- self.mock.start()
- self.mock_.start()
-
- super().enable()
-
- def disable(self) -> None:
- super().disable()
- self.mock.stop()
- self.mock_.stop()
- shutil.rmtree(self.options["CA_DIR"])
-
-
-__all__ = [
- "CRYPTOGRAPHY_VERSION",
- "DOC_DIR",
- "FIXTURES_DIR",
- "GECKODRIVER_PATH",
- "RUN_SELENIUM_TESTS",
- "dns",
- "rdn",
- "uri",
-]
diff --git a/ca/django_ca/tests/base/conftest_helpers.py b/ca/django_ca/tests/base/conftest_helpers.py
index 757c0e1d1..29c3eded8 100644
--- a/ca/django_ca/tests/base/conftest_helpers.py
+++ b/ca/django_ca/tests/base/conftest_helpers.py
@@ -12,7 +12,7 @@
# .
"""Helpers for pytest conftest."""
-import json
+
import os
import shutil
import sys
@@ -24,7 +24,6 @@
import cryptography
from cryptography import x509
-from cryptography.hazmat.primitives import serialization
import django
from django.conf import settings
@@ -36,7 +35,7 @@
from pytest_django.fixtures import SettingsWrapper
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import FIXTURES_DIR, timestamps
+from django_ca.tests.base.constants import CERT_DATA, FIXTURES_DIR, TIMESTAMPS
from django_ca.utils import int_to_hex
@@ -159,7 +158,7 @@ def fixture(
request: "SubRequest",
db: Any, # pylint: disable=unused-argument,invalid-name # usefixtures does not work for fixtures
) -> Iterator[CertificateAuthority]:
- data = fixture_data["certs"][name]
+ data = CERT_DATA[name]
pub = request.getfixturevalue(f"{name}_pub")
# Load any parent
@@ -167,7 +166,7 @@ def fixture(
if parent_name := data.get("parent"):
parent = request.getfixturevalue(parent_name)
- with freeze_time(timestamps["everything_valid"]):
+ with freeze_time(TIMESTAMPS["everything_valid"]):
ca = load_ca(name, pub, parent)
yield ca # NOTE: Yield must be outside the freeze-time block, or durations are wrong
@@ -183,7 +182,7 @@ def generate_usable_ca_fixture(
@pytest.fixture()
def fixture(request: "SubRequest", tmpcadir: SettingsWrapper) -> Iterator[CertificateAuthority]:
ca = request.getfixturevalue(name) # load the CA into the database
- data = fixture_data["certs"][name]
+ data = CERT_DATA[name]
shutil.copy(os.path.join(FIXTURES_DIR, data["key_filename"]), tmpcadir.CA_DIR)
yield ca
@@ -197,12 +196,12 @@ def generate_cert_fixture(name: str) -> typing.Callable[["SubRequest"], Iterator
@pytest.fixture()
def fixture(request: "SubRequest") -> Iterator[Certificate]:
sanitized_name = name.replace("-", "_")
- data = fixture_data["certs"][name]
+ data = CERT_DATA[name]
ca = request.getfixturevalue(data["ca"])
pub = request.getfixturevalue(f"{sanitized_name}_pub")
- with freeze_time(timestamps["everything_valid"]):
- cert = load_cert(ca, certs[name]["csr"]["pem"], pub, data.get("profile", ""))
+ with freeze_time(TIMESTAMPS["everything_valid"]):
+ cert = load_cert(ca, data["csr"]["pem"], pub, data.get("profile", ""))
yield cert # NOTE: Yield must be outside the freeze-time block, or durations are wrong
@@ -237,28 +236,6 @@ def load_ca(
return ca
-def _load_certificate_signing_requests() -> None:
- for name in usable_cert_names:
- with open(os.path.join(FIXTURES_DIR, f"{name}.csr"), "rb") as stream:
- pem_bytes = stream.read()
- certs[name]["csr"] = {
- "der": x509.load_pem_x509_csr(pem_bytes),
- "pem": pem_bytes.decode("utf-8"),
- }
-
-
-def _load_public_keys() -> None:
- for name in usable_ca_names + usable_cert_names:
- with open(os.path.join(FIXTURES_DIR, f"{name}.pub.der"), "rb") as stream:
- der_bytes = stream.read()
- certificate = x509.load_der_x509_certificate(der_bytes)
- certs[name]["pub"] = {
- "der": der_bytes,
- "loaded": x509.load_der_x509_certificate(der_bytes),
- "pem": certificate.public_bytes(serialization.Encoding.PEM).decode("utf-8"),
- }
-
-
def load_cert(
ca: CertificateAuthority, csr: x509.CertificateSigningRequest, pub: x509.Certificate, profile: str = ""
) -> Certificate:
@@ -269,34 +246,20 @@ def load_cert(
return cert
-with open(os.path.join(FIXTURES_DIR, "cert-data.json"), encoding="utf-8") as cert_data_stream:
- fixture_data = json.load(cert_data_stream)
-certs = fixture_data["certs"]
-
# Define various classes of certificates
usable_ca_names = [
- name for name, conf in fixture_data["certs"].items() if conf["type"] == "ca" and conf.get("key_filename")
+ name for name, conf in CERT_DATA.items() if conf["type"] == "ca" and conf.get("key_filename")
]
unusable_ca_names = [
- name
- for name, conf in fixture_data["certs"].items()
- if conf["type"] == "ca" and name not in usable_ca_names
+ name for name, conf in CERT_DATA.items() if conf["type"] == "ca" and name not in usable_ca_names
]
all_ca_names = usable_ca_names + unusable_ca_names
usable_cert_names = [
- name
- for name, conf in fixture_data["certs"].items()
- if conf["type"] == "cert" and conf["cat"] == "generated"
+ name for name, conf in CERT_DATA.items() if conf["type"] == "cert" and conf["cat"] == "generated"
]
unusable_cert_names = [
- name
- for name, conf in fixture_data["certs"].items()
- if conf["type"] == "cert" and name not in usable_ca_names
+ name for name, conf in CERT_DATA.items() if conf["type"] == "cert" and name not in usable_ca_names
]
interesting_certificate_names = ["child-cert", "all-extensions", "alt-extensions", "no-extensions"]
all_cert_names = usable_cert_names + unusable_cert_names
-
-# Load CSRs/public keys into certs
-_load_certificate_signing_requests()
-_load_public_keys()
diff --git a/ca/django_ca/tests/base/constants.py b/ca/django_ca/tests/base/constants.py
index 6f47c470b..05bda13e3 100644
--- a/ca/django_ca/tests/base/constants.py
+++ b/ca/django_ca/tests/base/constants.py
@@ -15,22 +15,30 @@
import json
import os
+import re
import sys
+from datetime import datetime, timedelta, timezone as tz
from importlib.metadata import version
from pathlib import Path
-from typing import List, Tuple
+from typing import Any, Dict, List, Tuple
import packaging.version
import cryptography
+from cryptography import x509
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives._serialization import Encoding
import django
-# PYLINT NOTE: lazy import so that just importing this module has no external dependencies
+from django_ca.constants import EXTENSION_KEYS
+from django_ca.extensions import serialize_extension
+from django_ca.tests.base.typehints import CsrDict, KeyDict, PubDict
+from django_ca.utils import add_colons, format_name
+
try:
- import tomllib # pylint: disable=import-outside-toplevel
+ import tomllib
except ImportError: # pragma: only py<3.11
- # pylint: disable-next=import-outside-toplevel
import tomli as tomllib # type: ignore[no-redef]
@@ -46,11 +54,12 @@ def _load_latest_version(versions: List[str]) -> Tuple[int, int]:
BASE_DIR = TEST_DIR.parent.parent # ca/
ROOT_DIR = BASE_DIR.parent # git repository root
-with open(ROOT_DIR / "pyproject.toml", "rb") as stream:
- PROJECT_CONFIG = tomllib.load(stream)
+with open(ROOT_DIR / "pyproject.toml", "rb") as pyproject_stream:
+ PROJECT_CONFIG = tomllib.load(pyproject_stream)
# Paths derived from ROOT_DIR
DOC_DIR = ROOT_DIR / "docs" / "source"
+SPHINX_FIXTURES_DIR = DOC_DIR / "_files"
GECKODRIVER_PATH = ROOT_DIR / "contrib" / "selenium" / "geckodriver"
if TOX_ENV_DIR := os.environ.get("TOX_ENV_DIR"): # pragma: no cover
@@ -85,14 +94,318 @@ def _load_latest_version(versions: List[str]) -> Tuple[int, int]:
FIXTURES_DATA = json.load(cert_data_stream)
CERT_DATA = FIXTURES_DATA["certs"]
+
+# Update some data from contrib (data is not in cert-data.json, since we don't generate them)
+CERT_DATA["multiple_ous"] = {
+ "name": "multiple_ous",
+ "subject": [
+ ["C", "US"],
+ ["O", "VeriSign, Inc."],
+ ["OU", "Class 3 Public Primary Certification Authority - G2"],
+ ["OU", "(c) 1998 VeriSign, Inc. - For authorized use only"],
+ ["OU", "VeriSign Trust Network"],
+ ],
+ "subject_str": "/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network", # noqa: E501
+ "cn": "",
+ "key_filename": False,
+ "csr_filename": False,
+ "pub_filename": os.path.join("contrib", "multiple_ous_and_no_ext.pem"),
+ "key_type": "RSA",
+ "cat": "contrib",
+ "type": "cert",
+ "valid_from": "1998-05-18 00:00:00",
+ "valid_until": "2028-08-01 23:59:59",
+ "ca": "root",
+ "serial": "7DD9FE07CFA81EB7107967FBA78934C6",
+ "md5": "A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9",
+ "sha1": "85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F",
+ "sha256": "83:CE:3C:12:29:68:8A:59:3D:48:5F:81:97:3C:0F:91:95:43:1E:DA:37:CC:5E:36:43:0E:79:C7:A8:88:63:8B", # noqa: E501
+ "sha512": "86:20:07:9F:8B:06:80:43:44:98:F6:7A:A4:22:DE:7E:2B:33:10:9B:65:72:79:C4:EB:F3:F3:0F:66:C8:6E:89:1D:4C:6C:09:1C:83:45:D1:25:6C:F8:65:EB:9A:B9:50:8F:26:A8:85:AE:3A:E4:8A:58:60:48:65:BB:44:B6:CE", # NOQA
+}
+CERT_DATA["cloudflare_1"] = {
+ "name": "cloudflare_1",
+ "subject": [
+ ["OU", "Domain Control Validated"],
+ ["OU", "PositiveSSL Multi-Domain"],
+ ["CN", "sni24142.cloudflaressl.com"],
+ ],
+ "subject_str": "/OU=Domain Control Validated/OU=PositiveSSL Multi-Domain/CN=sni24142.cloudflaressl.com",
+ "cn": "sni24142.cloudflaressl.com",
+ "key_filename": False,
+ "csr_filename": False,
+ "pub_filename": os.path.join("contrib", "cloudflare_1.pem"),
+ "cat": "contrib",
+ "type": "cert",
+ "key_type": "EC",
+ "valid_from": "2018-07-18 00:00:00",
+ "valid_until": "2019-01-24 23:59:59",
+ "ca": "root",
+ "serial": "92529ABD85F0A6A4D6C53FD1C91011C1",
+ "md5": "D6:76:03:E9:4F:3B:B0:F1:F7:E3:A1:40:80:8E:F0:4A",
+ "sha1": "71:BD:B8:21:80:BD:86:E8:E5:F4:2B:6D:96:82:B2:EF:19:53:ED:D3",
+ "sha256": "1D:8E:D5:41:E5:FF:19:70:6F:65:86:A9:A3:6F:DF:DE:F8:A0:07:22:92:71:9E:F1:CD:F8:28:37:39:02:E0:A1", # NOQA
+ "sha512": "FF:03:1B:8F:11:E8:A7:FF:91:4F:B9:97:E9:97:BC:77:37:C1:A7:69:86:F3:7C:E3:BB:BB:DF:A6:4F:0E:3C:C0:7F:B5:BC:CC:BD:0A:D5:EF:5F:94:55:E9:FF:48:41:34:B8:11:54:57:DD:90:85:41:2E:71:70:5E:FA:BA:E6:EA", # NOQA
+ "authority_information_access": {
+ "critical": False,
+ "value": {
+ "issuers": ["URI:http://crt.comodoca4.com/COMODOECCDomainValidationSecureServerCA2.crt"],
+ "ocsp": ["URI:http://ocsp.comodoca4.com"],
+ },
+ },
+ "authority_key_identifier": {
+ "critical": False,
+ "value": "40:09:61:67:F0:BC:83:71:4F:DE:12:08:2C:6F:D4:D4:2B:76:3D:96",
+ },
+ "basic_constraints": {
+ "critical": True,
+ "value": {"ca": False},
+ },
+ "crl_distribution_points": {
+ "value": [
+ {
+ "full_name": [
+ "URI:http://crl.comodoca4.com/COMODOECCDomainValidationSecureServerCA2.crl",
+ ],
+ }
+ ],
+ "critical": False,
+ },
+ "extended_key_usage": {
+ "critical": False,
+ "value": ["serverAuth", "clientAuth"],
+ },
+ "key_usage": {
+ "critical": True,
+ "value": ["digital_signature"],
+ },
+ "precert_poison": {"critical": True},
+ "subject_alternative_name": {
+ "value": [
+ "DNS:sni24142.cloudflaressl.com",
+ "DNS:*.animereborn.com",
+ "DNS:*.beglideas.ga",
+ "DNS:*.chroma.ink",
+ "DNS:*.chuckscleanings.ga",
+ "DNS:*.clipvuigiaitris.ga",
+ "DNS:*.cmvsjns.ga",
+ "DNS:*.competegraphs.ga",
+ "DNS:*.consoleprints.ga",
+ "DNS:*.copybreezes.ga",
+ "DNS:*.corphreyeds.ga",
+ "DNS:*.cyanigees.ga",
+ "DNS:*.dadpbears.ga",
+ "DNS:*.dahuleworldwides.ga",
+ "DNS:*.dailyopeningss.ga",
+ "DNS:*.daleylexs.ga",
+ "DNS:*.danajweinkles.ga",
+ "DNS:*.dancewthyogas.ga",
+ "DNS:*.darkmoosevpss.ga",
+ "DNS:*.daurat.com.ar",
+ "DNS:*.deltaberg.com",
+ "DNS:*.drjahanobgyns.ga",
+ "DNS:*.drunkgirliess.ga",
+ "DNS:*.duhiepkys.ga",
+ "DNS:*.dujuanjsqs.ga",
+ "DNS:*.dumbiseasys.ga",
+ "DNS:*.dumpsoftdrinkss.ga",
+ "DNS:*.dunhavenwoodss.ga",
+ "DNS:*.durabiliteas.ga",
+ "DNS:*.duxmangroups.ga",
+ "DNS:*.dvpdrivewayss.ga",
+ "DNS:*.dwellwizes.ga",
+ "DNS:*.dwwkouis.ga",
+ "DNS:*.entertastic.com",
+ "DNS:*.estudiogolber.com.ar",
+ "DNS:*.letsretro.team",
+ "DNS:*.maccuish.org.uk",
+ "DNS:*.madamsquiggles.com",
+ "DNS:*.sftw.ninja",
+ "DNS:*.spangenberg.io",
+ "DNS:*.timmutton.com.au",
+ "DNS:*.wyomingsexbook.com",
+ "DNS:*.ych.bid",
+ "DNS:animereborn.com",
+ "DNS:beglideas.ga",
+ "DNS:chroma.ink",
+ "DNS:chuckscleanings.ga",
+ "DNS:clipvuigiaitris.ga",
+ "DNS:cmvsjns.ga",
+ "DNS:competegraphs.ga",
+ "DNS:consoleprints.ga",
+ "DNS:copybreezes.ga",
+ "DNS:corphreyeds.ga",
+ "DNS:cyanigees.ga",
+ "DNS:dadpbears.ga",
+ "DNS:dahuleworldwides.ga",
+ "DNS:dailyopeningss.ga",
+ "DNS:daleylexs.ga",
+ "DNS:danajweinkles.ga",
+ "DNS:dancewthyogas.ga",
+ "DNS:darkmoosevpss.ga",
+ "DNS:daurat.com.ar",
+ "DNS:deltaberg.com",
+ "DNS:drjahanobgyns.ga",
+ "DNS:drunkgirliess.ga",
+ "DNS:duhiepkys.ga",
+ "DNS:dujuanjsqs.ga",
+ "DNS:dumbiseasys.ga",
+ "DNS:dumpsoftdrinkss.ga",
+ "DNS:dunhavenwoodss.ga",
+ "DNS:durabiliteas.ga",
+ "DNS:duxmangroups.ga",
+ "DNS:dvpdrivewayss.ga",
+ "DNS:dwellwizes.ga",
+ "DNS:dwwkouis.ga",
+ "DNS:entertastic.com",
+ "DNS:estudiogolber.com.ar",
+ "DNS:letsretro.team",
+ "DNS:maccuish.org.uk",
+ "DNS:madamsquiggles.com",
+ "DNS:sftw.ninja",
+ "DNS:spangenberg.io",
+ "DNS:timmutton.com.au",
+ "DNS:wyomingsexbook.com",
+ "DNS:ych.bid",
+ ]
+ },
+ "subject_key_identifier": {
+ "critical": False,
+ "value": "05:86:D8:B4:ED:A9:7E:23:EE:2E:E7:75:AA:3B:2C:06:08:2A:93:B2",
+ },
+ "certificate_policies": {
+ "value": [
+ {
+ "policy_identifier": "1.3.6.1.4.1.6449.1.2.2.7",
+ "policy_qualifiers": ["https://secure.comodo.com/CPS"],
+ },
+ {"policy_identifier": "2.23.140.1.2.1"},
+ ],
+ "critical": False,
+ },
+}
+
+
+def _load_key(data: Dict[Any, Any]) -> KeyDict:
+ with open(data["key_der_path"], "rb") as stream:
+ raw = stream.read()
+
+ parsed = serialization.load_der_private_key(
+ raw, password=data.get("password"), unsafe_skip_rsa_key_validation=True
+ )
+
+ return {
+ "der": raw,
+ "pem": parsed.private_bytes(
+ Encoding.PEM,
+ serialization.PrivateFormat.PKCS8,
+ encryption_algorithm=serialization.NoEncryption(),
+ ).decode(),
+ "parsed": parsed, # type: ignore[typeddict-item] # we do not support all key types
+ }
+
+
+def _load_csr(data: Dict[Any, Any]) -> CsrDict:
+ with open(FIXTURES_DIR / data["csr_filename"], "rb") as stream:
+ raw = stream.read()
+
+ parsed = x509.load_pem_x509_csr(raw)
+ return {
+ "pem": raw.decode("utf-8"),
+ "parsed": parsed,
+ }
+
+
+def _load_pub(data: Dict[str, Any]) -> PubDict:
+ if pub_der_path := data.get("pub_der_path"):
+ with open(pub_der_path, "rb") as stream:
+ der = stream.read()
+ parsed = x509.load_der_x509_certificate(der)
+ pem = parsed.public_bytes(Encoding.PEM).decode("utf-8")
+ else:
+ pub_path = data["pub_path"]
+ with open(pub_path, "rb") as stream:
+ pub_pem_bytes = stream.read()
+ parsed = x509.load_pem_x509_certificate(pub_pem_bytes)
+ pem = pub_pem_bytes.decode("utf-8")
+ der = parsed.public_bytes(Encoding.DER)
+
+ return {"pem": pem, "parsed": parsed, "der": der}
+
+
+# Augment data with various pre-computed paths
for _name, _cert_data in CERT_DATA.items():
+ if _cert_data["cat"] == "sphinx-contrib":
+ basedir = SPHINX_FIXTURES_DIR / _cert_data["type"]
+ else:
+ basedir = FIXTURES_DIR
+
if _key_filename := _cert_data.get("key_filename"):
- CERT_DATA[_name]["key_path"] = FIXTURES_DIR / _cert_data["key_filename"]
+ _cert_data["key_path"] = basedir / _cert_data["key_filename"]
if _key_der_filename := _cert_data.get("key_der_filename"):
- CERT_DATA[_name]["key_der_path"] = FIXTURES_DIR / _cert_data["key_der_filename"]
+ _cert_data["key_der_path"] = basedir / _cert_data["key_der_filename"]
if _pub_der_filename := _cert_data.get("pub_der_filename"):
- CERT_DATA[_name]["pub_der_path"] = FIXTURES_DIR / _cert_data["pub_der_filename"]
+ _cert_data["pub_der_path"] = basedir / _cert_data["pub_der_filename"]
if _password := _cert_data.get("password"):
- CERT_DATA[_name]["password"] = _cert_data["password"].encode("utf-8")
- CERT_DATA[_name]["pub_path"] = FIXTURES_DIR / _cert_data["pub_filename"]
- CERT_DATA[_name]["pub_path"] = FIXTURES_DIR / _cert_data["pub_filename"]
+ _cert_data["password"] = _cert_data["password"].encode("utf-8")
+ _cert_data["pub_path"] = basedir / _cert_data["pub_filename"]
+
+ if _cert_data["type"] == "ca":
+ _cert_data.setdefault("children", [])
+ _cert_data["children"] = [(k, add_colons(v)) for k, v in _cert_data["children"]]
+
+ # Load data from files
+ # if key_filename := _cert_data["key_filename"]:
+ # _cert_data["key"] = _load_key(key_filename, _cert_data)
+ if _cert_data.get("key_der_path"):
+ _cert_data["key"] = _load_key(_cert_data)
+ if _cert_data.get("csr_filename"):
+ _cert_data["csr"] = _load_csr(_cert_data)
+ _cert_data["pub"] = _load_pub(_cert_data)
+ _cert: x509.Certificate = _cert_data["pub"]["parsed"]
+
+ # Data derived from public key
+ _cert_data["issuer"] = _cert.issuer
+ _cert_data["issuer_str"] = format_name(_cert_data["issuer"])
+ _cert_data["serial_colons"] = add_colons(_cert_data["serial"])
+ _cert_data["valid_from"] = _cert.not_valid_before # TODO: make tz-aware
+ _cert_data["valid_until"] = _cert.not_valid_after # TODO: make tz-aware
+ _cert_data["valid_from_str"] = _cert.not_valid_before.replace(tzinfo=tz.utc).isoformat(" ")
+ _cert_data["valid_until_str"] = _cert.not_valid_after.replace(tzinfo=tz.utc).isoformat(" ")
+
+ for extension in _cert.extensions:
+ try:
+ key = EXTENSION_KEYS[extension.oid]
+ except KeyError: # unknown extensions from StartSSL CA
+ continue
+ _cert_data[key] = extension
+ _cert_data[f"{key}_serialized"] = serialize_extension(extension)["value"]
+
+# Calculate some fixed timestamps that we reuse throughout the tests
+TIMESTAMPS = {
+ "base": datetime.fromisoformat(FIXTURES_DATA["timestamp"]),
+ "before_everything": datetime(1990, 1, 1, tzinfo=tz.utc),
+}
+TIMESTAMPS["before_cas"] = TIMESTAMPS["base"] - timedelta(days=1)
+TIMESTAMPS["before_child"] = TIMESTAMPS["base"] + timedelta(days=1)
+TIMESTAMPS["after_child"] = TIMESTAMPS["base"] + timedelta(days=4)
+TIMESTAMPS["ca_certs_valid"] = TIMESTAMPS["base"] + timedelta(days=7)
+TIMESTAMPS["profile_certs_valid"] = TIMESTAMPS["base"] + timedelta(days=12)
+
+# When creating fixtures, latest valid_from of any generated cert is 20 days, we need to be after that
+TIMESTAMPS["everything_valid"] = TIMESTAMPS["base"] + timedelta(days=23)
+TIMESTAMPS["everything_valid_naive"] = TIMESTAMPS["everything_valid"].astimezone(tz.utc).replace(tzinfo=None)
+TIMESTAMPS["cas_expired"] = TIMESTAMPS["base"] + timedelta(days=731, seconds=3600)
+TIMESTAMPS["ca_certs_expiring"] = CERT_DATA["root-cert"]["valid_until"] - timedelta(days=3)
+TIMESTAMPS["ca_certs_expired"] = CERT_DATA["root-cert"]["valid_until"] + timedelta(seconds=3600)
+TIMESTAMPS["profile_certs_expired"] = CERT_DATA["profile-server"]["valid_until"] + timedelta(seconds=3600)
+TIMESTAMPS["everything_expired"] = TIMESTAMPS["base"] + timedelta(days=365 * 20)
+
+# Regex used by certbot to split PEM-encoded certificate chains/bundles as of 2022-01-23. See also:
+# https://github.com/certbot/certbot/blob/master/certbot/certbot/crypto_util.py
+CERT_PEM_REGEX = re.compile(
+ b"""-----BEGIN CERTIFICATE-----\r?
+.+?\r?
+-----END CERTIFICATE-----\r?
+""",
+ re.DOTALL, # DOTALL (/s) because the base64text may include newlines
+)
diff --git a/ca/django_ca/tests/base/mixins.py b/ca/django_ca/tests/base/mixins.py
index 91e6fea88..a2437af6e 100644
--- a/ca/django_ca/tests/base/mixins.py
+++ b/ca/django_ca/tests/base/mixins.py
@@ -60,11 +60,11 @@
pre_create_ca,
pre_sign_cert,
)
-from django_ca.tests.base import certs, timestamps, uri
from django_ca.tests.base.assertions import assert_change_response, assert_changelist_response
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import DjangoCAModelTypeVar
-from django_ca.tests.base.utils import basic_constraints, certificate_policies
-from django_ca.utils import add_colons, ca_storage, parse_general_name
+from django_ca.tests.base.utils import basic_constraints, certificate_policies, uri
+from django_ca.utils import ca_storage, parse_general_name
if typing.TYPE_CHECKING:
# Use SimpleTestCase as base class when type checking. This way mypy will know about attributes/methods
@@ -125,9 +125,9 @@ def setUp(self) -> None:
def load_named_cas(self, cas: Union[str, Tuple[str, ...]]) -> Tuple[str, ...]:
"""Load CAs by the given name."""
if cas == "__all__":
- cas = tuple(k for k, v in certs.items() if v.get("type") == "ca")
+ cas = tuple(k for k, v in CERT_DATA.items() if v.get("type") == "ca")
elif cas == "__usable__":
- cas = tuple(k for k, v in certs.items() if v.get("type") == "ca" and v["key_filename"])
+ cas = tuple(k for k, v in CERT_DATA.items() if v.get("type") == "ca" and v["key_filename"])
elif isinstance(cas, str): # pragma: no cover
self.fail(f"{cas}: Unknown alias for load_cas.")
@@ -135,16 +135,18 @@ def load_named_cas(self, cas: Union[str, Tuple[str, ...]]) -> Tuple[str, ...]:
cas = tuple(ca for ca in cas if ca not in self.cas)
# Load all CAs (sort by len() of parent so that root CAs are loaded first)
- for name in sorted(cas, key=lambda n: len(certs[n].get("parent", ""))):
+ for name in sorted(cas, key=lambda n: len(CERT_DATA[n].get("parent", ""))):
self.cas[name] = self.load_ca(name)
return cas
def load_named_certs(self, names: Union[str, Tuple[str, ...]]) -> Tuple[str, ...]:
"""Load certs by the given name."""
if names == "__all__":
- names = tuple(k for k, v in certs.items() if v.get("type") == "cert")
+ names = tuple(k for k, v in CERT_DATA.items() if v.get("type") == "cert")
elif names == "__usable__":
- names = tuple(k for k, v in certs.items() if v.get("type") == "cert" and v["cat"] == "generated")
+ names = tuple(
+ k for k, v in CERT_DATA.items() if v.get("type") == "cert" and v["cat"] == "generated"
+ )
elif isinstance(names, str): # pragma: no cover
self.fail(f"{names}: Unknown alias for load_certs.")
@@ -155,7 +157,7 @@ def load_named_certs(self, names: Union[str, Tuple[str, ...]]) -> Tuple[str, ...
try:
self.certs[name] = self.load_named_cert(name)
except CertificateAuthority.DoesNotExist: # pragma: no cover
- self.fail(f'{certs[name]["ca"]}: Could not load CertificateAuthority.')
+ self.fail(f'{CERT_DATA[name]["ca"]}: Could not load CertificateAuthority.')
return names
def absolute_uri(self, name: str, hostname: Optional[str] = None, **kwargs: Any) -> str:
@@ -814,7 +816,7 @@ def crl_profiles(self) -> Dict[str, Dict[str, Any]]:
for config in profiles.values():
config.setdefault("OVERRIDES", {})
- for data in [d for d in certs.values() if d.get("type") == "ca"]:
+ for data in [d for d in CERT_DATA.values() if d.get("type") == "ca"]:
config["OVERRIDES"][data["serial"]] = {}
if data.get("password"):
config["OVERRIDES"][data["serial"]]["password"] = data["password"]
@@ -898,11 +900,11 @@ def freeze_time(
) -> Iterator[Union[FrozenDateTimeFactory, StepTickTimeFactory]]:
"""Context manager to freeze time to a given timestamp.
- If `timestamp` is a str that is in the `timestamps` dict (e.g. "everything-valid"), use that
+ If `timestamp` is a str that is in the `TIMESTAMPS` dict (e.g. "everything-valid"), use that
timestamp.
"""
if isinstance(timestamp, str): # pragma: no branch
- timestamp = timestamps[timestamp]
+ timestamp = TIMESTAMPS[timestamp]
with freeze_time(timestamp) as frozen:
yield frozen
@@ -910,7 +912,8 @@ def freeze_time(
def get_cert_context(self, name: str) -> Dict[str, Any]:
"""Get a dictionary suitable for testing output based on the dictionary in basic.certs."""
ctx: Dict[str, Any] = {}
- for key, value in sorted(certs[name].items()):
+
+ for key, value in sorted(CERT_DATA[name].items()):
# Handle cryptography extensions
if key == "precert_poison":
ctx["precert_poison"] = "* Precert Poison (critical):\n Yes"
@@ -921,27 +924,19 @@ def get_cert_context(self, name: str) -> Dict[str, Any]:
ctx[f"{key}_critical"] = ""
ctx[f"{key}_text"] = textwrap.indent(extension_as_text(value.value), " ")
- elif key == "precertificate_signed_certificate_timestamps_serialized":
- ctx["sct_critical"] = " (critical)" if value["critical"] else ""
- ctx["sct_values"] = []
- for val in value["value"]:
- ctx["sct_values"].append(val)
- elif key == "precertificate_signed_certificate_timestamps":
- continue # special extension b/c it cannot be created
elif key == "path_length":
ctx[key] = value
ctx[f"{key}_text"] = "unlimited" if value is None else value
else:
ctx[key] = value
- if certs[name].get("parent"):
- parent = certs[certs[name]["parent"]]
- ctx["parent_name"] = parent["name"]
- ctx["parent_serial"] = parent["serial"]
- ctx["parent_serial_colons"] = add_colons(parent["serial"])
+ if parent := CERT_DATA[name].get("parent"):
+ ctx["parent_name"] = CERT_DATA[parent]["name"]
+ ctx["parent_serial"] = CERT_DATA[parent]["serial"]
+ ctx["parent_serial_colons"] = CERT_DATA[parent]["serial_colons"]
- if certs[name]["key_filename"] is not False:
- ctx["key_path"] = ca_storage.path(certs[name]["key_filename"])
+ if CERT_DATA[name]["key_filename"] is not False:
+ ctx["key_path"] = ca_storage.path(CERT_DATA[name]["key_filename"])
return ctx
@classmethod
@@ -956,15 +951,15 @@ def load_ca(
"""Load a CA from one of the preloaded files."""
path = f"{name}.key"
if parsed is None:
- parsed = certs[name]["pub"]["parsed"]
- if parent is None and certs[name].get("parent"):
- parent = CertificateAuthority.objects.get(name=certs[name]["parent"])
+ parsed = CERT_DATA[name]["pub"]["parsed"]
+ if parent is None and CERT_DATA[name].get("parent"):
+ parent = CertificateAuthority.objects.get(name=CERT_DATA[name]["parent"])
# set some default values
- kwargs.setdefault("issuer_alt_name", certs[name].get("issuer_alternative_name", ""))
- kwargs.setdefault("crl_url", certs[name].get("crl_url", ""))
- kwargs.setdefault("ocsp_url", certs[name].get("ocsp_url", ""))
- kwargs.setdefault("issuer_url", certs[name].get("issuer_url", ""))
+ kwargs.setdefault("issuer_alt_name", CERT_DATA[name].get("issuer_alternative_name", ""))
+ kwargs.setdefault("crl_url", CERT_DATA[name].get("crl_url", ""))
+ kwargs.setdefault("ocsp_url", CERT_DATA[name].get("ocsp_url", ""))
+ kwargs.setdefault("issuer_url", CERT_DATA[name].get("issuer_url", ""))
ca = CertificateAuthority(name=name, private_key_path=path, enabled=enabled, parent=parent, **kwargs)
ca.update_certificate(parsed) # calculates serial etc
@@ -974,7 +969,7 @@ def load_ca(
@classmethod
def load_named_cert(cls, name: str) -> Certificate:
"""Load a certificate with the given mame."""
- data = certs[name]
+ data = CERT_DATA[name]
ca = CertificateAuthority.objects.get(name=data["ca"])
csr = data.get("csr", {}).get("parsed", "")
profile = data.get("profile", "")
@@ -1062,14 +1057,14 @@ def reverse(self, name: str, *args: Any, **kwargs: Any) -> str:
def usable_cas(self) -> Iterator[Tuple[str, CertificateAuthority]]:
"""Yield loaded generated certificates."""
for name, ca in self.cas.items():
- if certs[name]["key_filename"]:
+ if CERT_DATA[name]["key_filename"]:
yield name, ca
@property
def usable_certs(self) -> Iterator[Tuple[str, Certificate]]:
"""Yield loaded generated certificates."""
for name, cert in self.certs.items():
- if certs[name]["cat"] == "generated":
+ if CERT_DATA[name]["cat"] == "generated":
yield name, cert
diff --git a/ca/django_ca/tests/base/typehints.py b/ca/django_ca/tests/base/typehints.py
index 210455567..e7cf39b76 100644
--- a/ca/django_ca/tests/base/typehints.py
+++ b/ca/django_ca/tests/base/typehints.py
@@ -16,6 +16,9 @@
import typing
from typing import Any, Dict
+from cryptography import x509
+from cryptography.hazmat.primitives.asymmetric.types import CertificateIssuerPrivateKeyTypes
+
from django_ca.models import DjangoCAModel
if typing.TYPE_CHECKING:
@@ -57,4 +60,9 @@ class FixtureData(typing.TypedDict):
certs: Dict[str, CertFixtureData]
+KeyDict = typing.TypedDict("KeyDict", {"pem": str, "parsed": CertificateIssuerPrivateKeyTypes, "der": bytes})
+PubDict = typing.TypedDict("PubDict", {"pem": str, "parsed": x509.Certificate, "der": bytes})
+CsrDict = typing.TypedDict("CsrDict", {"pem": str, "parsed": x509.CertificateSigningRequest})
+
+
__all__ = ["HttpResponse", "User"]
diff --git a/ca/django_ca/tests/base/utils.py b/ca/django_ca/tests/base/utils.py
index 6f359d450..ad2701b22 100644
--- a/ca/django_ca/tests/base/utils.py
+++ b/ca/django_ca/tests/base/utils.py
@@ -12,14 +12,26 @@
# .
"""Utility functions used in testing."""
+import inspect
+import ipaddress
+import os
+import shutil
+import tempfile
import typing
+from contextlib import contextmanager
from datetime import datetime
-from typing import Iterable, Optional, Union
+from typing import Any, Iterable, Iterator, Optional, Tuple, Union
+from unittest.mock import patch
from cryptography import x509
from cryptography.x509.oid import AuthorityInformationAccessOID, ExtensionOID
+from django.test import override_settings
+
from django_ca.models import X509CertMixin
+from django_ca.profiles import profiles
+from django_ca.tests.base.constants import CERT_DATA, FIXTURES_DIR
+from django_ca.utils import ca_storage
def authority_information_access(
@@ -186,3 +198,82 @@ def subject_key_identifier(
def tls_feature(*features: x509.TLSFeatureType, critical: bool = False) -> x509.Extension[x509.TLSFeature]:
"""Shortcut for getting a TLSFeature extension."""
return x509.Extension(oid=ExtensionOID.TLS_FEATURE, critical=critical, value=x509.TLSFeature(features))
+
+
+FuncTypeVar = typing.TypeVar("FuncTypeVar", bound=typing.Callable[..., Any])
+
+
+def dns(name: str) -> x509.DNSName: # just a shortcut
+ """Shortcut to get a :py:class:`cg:cryptography.x509.DNSName`."""
+ return x509.DNSName(name)
+
+
+def uri(url: str) -> x509.UniformResourceIdentifier: # just a shortcut
+ """Shortcut to get a :py:class:`cg:cryptography.x509.UniformResourceIdentifier`."""
+ return x509.UniformResourceIdentifier(url)
+
+
+def ip( # pylint: disable=invalid-name # just a shortcut
+ name: Union[ipaddress.IPv4Address, ipaddress.IPv6Address, ipaddress.IPv4Network, ipaddress.IPv6Network]
+) -> x509.IPAddress:
+ """Shortcut to get a :py:class:`cg:cryptography.x509.IPAddress`."""
+ return x509.IPAddress(name)
+
+
+def rdn(
+ name: Iterable[Tuple[x509.ObjectIdentifier, str]]
+) -> x509.RelativeDistinguishedName: # just a shortcut
+ """Shortcut to get a :py:class:`cg:cryptography.x509.RelativeDistinguishedName`."""
+ return x509.RelativeDistinguishedName([x509.NameAttribute(*t) for t in name])
+
+
+@contextmanager
+def mock_cadir(path: str) -> Iterator[None]:
+ """Contextmanager to set the CA_DIR to a given path without actually creating it."""
+ with override_settings(CA_DIR=path), patch.object(ca_storage, "location", path), patch.object(
+ ca_storage, "_location", path
+ ):
+ yield
+
+
+class override_tmpcadir(override_settings): # pylint: disable=invalid-name; in line with parent class
+ """Sets the CA_DIR directory to a temporary directory.
+
+ .. NOTE: This also takes any additional settings.
+ """
+
+ def __call__(self, test_func: FuncTypeVar) -> FuncTypeVar:
+ if not inspect.isfunction(test_func):
+ raise ValueError("Only functions can use override_tmpcadir()")
+ return super().__call__(test_func) # type: ignore[return-value] # cannot figure out what's here
+
+ def enable(self) -> None:
+ self.options["CA_DIR"] = tempfile.mkdtemp()
+
+ # copy CAs
+ for filename in [v["key_filename"] for v in CERT_DATA.values() if v["key_filename"] is not False]:
+ shutil.copy(os.path.join(FIXTURES_DIR, filename), self.options["CA_DIR"])
+
+ # Copy OCSP public key (required for OCSP tests)
+ shutil.copy(
+ os.path.join(FIXTURES_DIR, CERT_DATA["profile-ocsp"]["pub_filename"]), self.options["CA_DIR"]
+ )
+
+ # pylint: disable=attribute-defined-outside-init
+ self.mock = patch.object(ca_storage, "location", self.options["CA_DIR"])
+ self.mock_ = patch.object(ca_storage, "_location", self.options["CA_DIR"])
+ # pylint: enable=attribute-defined-outside-init
+
+ # Reset profiles, so that they are loaded again on first access
+ profiles._reset() # pylint: disable=protected-access
+
+ self.mock.start()
+ self.mock_.start()
+
+ super().enable()
+
+ def disable(self) -> None:
+ super().disable()
+ self.mock.stop()
+ self.mock_.stop()
+ shutil.rmtree(self.options["CA_DIR"])
diff --git a/ca/django_ca/tests/commands/test_cache_crls.py b/ca/django_ca/tests/commands/test_cache_crls.py
index 7be753db1..9bba25c70 100644
--- a/ca/django_ca/tests/commands/test_cache_crls.py
+++ b/ca/django_ca/tests/commands/test_cache_crls.py
@@ -21,8 +21,9 @@
from freezegun import freeze_time
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
from django_ca.utils import get_crl_cache_key
@@ -32,7 +33,7 @@ class CacheCRLsTestCase(TestCaseMixin, TestCase):
load_cas = "__usable__"
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_basic(self) -> None:
"""Test the basic command.
diff --git a/ca/django_ca/tests/commands/test_convert_timestamps.py b/ca/django_ca/tests/commands/test_convert_timestamps.py
index c7dedfc1c..3870a932f 100644
--- a/ca/django_ca/tests/commands/test_convert_timestamps.py
+++ b/ca/django_ca/tests/commands/test_convert_timestamps.py
@@ -19,14 +19,14 @@
from django_ca import ca_settings
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeChallenge, AcmeOrder
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
INPUT_PATH = "django_ca.management.commands.convert_timestamps.input"
@override_settings(USE_TZ=False)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class ConvertTimestampsTestCase(TestCaseMixin, TestCase):
"""Test the convert_timestamps management command."""
@@ -40,11 +40,11 @@ def test_minimal_conversion(self) -> None:
acme_auth = AcmeAuthorization.objects.create(order=acme_order)
acme_challenge = AcmeChallenge.objects.create(auth=acme_auth)
- self.assertEqual(self.ca.created, timestamps["everything_valid_naive"])
- self.assertEqual(self.cert.created, timestamps["everything_valid_naive"])
- self.assertEqual(acme_account.created, timestamps["everything_valid_naive"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.cert.created, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(acme_account.created, TIMESTAMPS["everything_valid_naive"])
self.assertEqual(
- acme_order.expires, timestamps["everything_valid_naive"] + ca_settings.ACME_ORDER_VALIDITY
+ acme_order.expires, TIMESTAMPS["everything_valid_naive"] + ca_settings.ACME_ORDER_VALIDITY
)
self.assertIsNone(acme_challenge.validated)
@@ -57,11 +57,11 @@ def test_minimal_conversion(self) -> None:
acme_order.refresh_from_db()
acme_challenge.refresh_from_db()
- self.assertEqual(self.ca.created, timestamps["everything_valid"])
- self.assertEqual(self.cert.created, timestamps["everything_valid"])
- self.assertEqual(acme_account.created, timestamps["everything_valid"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.cert.created, TIMESTAMPS["everything_valid"])
+ self.assertEqual(acme_account.created, TIMESTAMPS["everything_valid"])
self.assertEqual(
- acme_order.expires, timestamps["everything_valid"] + ca_settings.ACME_ORDER_VALIDITY
+ acme_order.expires, TIMESTAMPS["everything_valid"] + ca_settings.ACME_ORDER_VALIDITY
)
self.assertIsNone(self.ca.revoked_date)
self.assertIsNone(self.ca.compromised)
@@ -73,7 +73,7 @@ def test_minimal_conversion(self) -> None:
def test_full_conversion(self) -> None:
"""Test conversion with all optional timestamps set."""
- now = timestamps["everything_valid_naive"]
+ now = TIMESTAMPS["everything_valid_naive"]
self.ca.revoked_date = now
self.ca.compromised = now
self.ca.save()
@@ -86,15 +86,15 @@ def test_full_conversion(self) -> None:
acme_auth = AcmeAuthorization.objects.create(order=acme_order)
acme_challenge = AcmeChallenge.objects.create(auth=acme_auth, validated=now)
- self.assertEqual(self.ca.created, timestamps["everything_valid_naive"])
- self.assertEqual(self.ca.revoked_date, timestamps["everything_valid_naive"])
- self.assertEqual(self.ca.compromised, timestamps["everything_valid_naive"])
- self.assertEqual(self.cert.created, timestamps["everything_valid_naive"])
- self.assertEqual(self.cert.revoked_date, timestamps["everything_valid_naive"])
- self.assertEqual(self.cert.compromised, timestamps["everything_valid_naive"])
- self.assertEqual(acme_account.created, timestamps["everything_valid_naive"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.ca.revoked_date, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.ca.compromised, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.cert.created, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(self.cert.compromised, TIMESTAMPS["everything_valid_naive"])
+ self.assertEqual(acme_account.created, TIMESTAMPS["everything_valid_naive"])
self.assertEqual(
- acme_order.expires, timestamps["everything_valid_naive"] + ca_settings.ACME_ORDER_VALIDITY
+ acme_order.expires, TIMESTAMPS["everything_valid_naive"] + ca_settings.ACME_ORDER_VALIDITY
)
self.assertEqual(acme_order.not_before, now)
self.assertEqual(acme_order.not_after, now)
@@ -109,28 +109,28 @@ def test_full_conversion(self) -> None:
acme_order.refresh_from_db()
acme_challenge.refresh_from_db()
- self.assertEqual(self.ca.created, timestamps["everything_valid"])
- self.assertEqual(self.ca.revoked_date, timestamps["everything_valid"])
- self.assertEqual(self.ca.compromised, timestamps["everything_valid"])
- self.assertEqual(self.cert.created, timestamps["everything_valid"])
- self.assertEqual(self.cert.revoked_date, timestamps["everything_valid"])
- self.assertEqual(self.cert.compromised, timestamps["everything_valid"])
- self.assertEqual(acme_account.created, timestamps["everything_valid"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.ca.revoked_date, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.ca.compromised, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.cert.created, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid"])
+ self.assertEqual(self.cert.compromised, TIMESTAMPS["everything_valid"])
+ self.assertEqual(acme_account.created, TIMESTAMPS["everything_valid"])
self.assertEqual(
- acme_order.expires, timestamps["everything_valid"] + ca_settings.ACME_ORDER_VALIDITY
+ acme_order.expires, TIMESTAMPS["everything_valid"] + ca_settings.ACME_ORDER_VALIDITY
)
- self.assertEqual(acme_order.not_before, timestamps["everything_valid"])
- self.assertEqual(acme_order.not_after, timestamps["everything_valid"])
- self.assertEqual(acme_challenge.validated, timestamps["everything_valid"])
+ self.assertEqual(acme_order.not_before, TIMESTAMPS["everything_valid"])
+ self.assertEqual(acme_order.not_after, TIMESTAMPS["everything_valid"])
+ self.assertEqual(acme_challenge.validated, TIMESTAMPS["everything_valid"])
def test_no_confirmation(self) -> None:
"""Test that nothing happens if the user doesn't give confirmation."""
- self.assertEqual(self.ca.created, timestamps["everything_valid_naive"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid_naive"])
with self.settings(USE_TZ=True), self.patch(INPUT_PATH, return_value="no"):
out, err = self.cmd("convert_timestamps")
self.assertIn("Aborting.", out)
self.ca.refresh_from_db()
- self.assertEqual(self.ca.created, timestamps["everything_valid_naive"])
+ self.assertEqual(self.ca.created, TIMESTAMPS["everything_valid_naive"])
def test_use_tz_is_false(self) -> None:
"""Test error when USE_TZ=False."""
diff --git a/ca/django_ca/tests/commands/test_dump_ca.py b/ca/django_ca/tests/commands/test_dump_ca.py
index 3684e8a18..76e19b5e8 100644
--- a/ca/django_ca/tests/commands/test_dump_ca.py
+++ b/ca/django_ca/tests/commands/test_dump_ca.py
@@ -22,8 +22,8 @@
from django.test import TestCase
from django_ca import ca_settings
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
class DumpCATestCase(TestCaseMixin, TestCase):
diff --git a/ca/django_ca/tests/commands/test_dump_cert.py b/ca/django_ca/tests/commands/test_dump_cert.py
index ce0c60c0d..b363393ac 100644
--- a/ca/django_ca/tests/commands/test_dump_cert.py
+++ b/ca/django_ca/tests/commands/test_dump_cert.py
@@ -22,8 +22,8 @@
from django.test import TestCase
from django_ca import ca_settings
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
class DumpCertTestCase(TestCaseMixin, TestCase):
diff --git a/ca/django_ca/tests/commands/test_dump_crl.py b/ca/django_ca/tests/commands/test_dump_crl.py
index c6352c8bf..cbb6b7243 100644
--- a/ca/django_ca/tests/commands/test_dump_crl.py
+++ b/ca/django_ca/tests/commands/test_dump_crl.py
@@ -30,11 +30,12 @@
from django_ca import ca_settings
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class DumpCRLTestCase(TestCaseMixin, TestCase):
"""Test the dump_crl management command."""
@@ -157,7 +158,7 @@ def test_password(self) -> None:
"dump_crl",
ca=ca,
scope="user",
- password=certs["pwd"]["password"],
+ password=CERT_DATA["pwd"]["password"],
stdout=BytesIO(),
stderr=BytesIO(),
)
diff --git a/ca/django_ca/tests/commands/test_edit_ca.py b/ca/django_ca/tests/commands/test_edit_ca.py
index 0937d4cd7..c96e60bd1 100644
--- a/ca/django_ca/tests/commands/test_edit_ca.py
+++ b/ca/django_ca/tests/commands/test_edit_ca.py
@@ -18,8 +18,8 @@
from django_ca import ca_settings
from django_ca.models import CertificateAuthority
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
class EditCATestCase(TestCaseMixin, TestCase):
diff --git a/ca/django_ca/tests/commands/test_import_ca.py b/ca/django_ca/tests/commands/test_import_ca.py
index 59e29b556..f2476b603 100644
--- a/ca/django_ca/tests/commands/test_import_ca.py
+++ b/ca/django_ca/tests/commands/test_import_ca.py
@@ -28,9 +28,9 @@
from django_ca import ca_settings
from django_ca.models import CertificateAuthority
-from django_ca.tests.base import mock_cadir, override_tmpcadir, timestamps
-from django_ca.tests.base.constants import CERT_DATA
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import mock_cadir, override_tmpcadir
class ImportCATest(TestCaseMixin, TestCase):
@@ -48,7 +48,7 @@ def import_ca(self, *args: str) -> CertificateAuthority:
return CertificateAuthority.objects.get(name=self.hostname)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_basic(self) -> None:
"""Test basic import command.
@@ -103,7 +103,7 @@ def test_basic(self) -> None:
self.assertIs(ca.acme_requires_contact, True)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_der(self) -> None:
"""Test importing a der key.
@@ -155,7 +155,7 @@ def test_der(self) -> None:
self.assertEqual(ca.serial, data["serial"])
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_password(self) -> None:
"""Test importing a CA with a password for the private key.
diff --git a/ca/django_ca/tests/commands/test_import_cert.py b/ca/django_ca/tests/commands/test_import_cert.py
index b1a9143fe..617a5640b 100644
--- a/ca/django_ca/tests/commands/test_import_cert.py
+++ b/ca/django_ca/tests/commands/test_import_cert.py
@@ -20,12 +20,12 @@
from freezegun import freeze_time
from django_ca.models import Certificate
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
-from django_ca.tests.base.constants import CERT_DATA
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class ImportCertTest(TestCaseMixin, TestCase):
"""Main test class for this command."""
@@ -39,7 +39,7 @@ def test_basic(self) -> None:
self.assertEqual(out, "")
self.assertEqual(err, "")
- cert = Certificate.objects.get(serial=certs["root-cert"]["serial"])
+ cert = Certificate.objects.get(serial=CERT_DATA["root-cert"]["serial"])
self.assertSignature([self.ca], cert)
self.assertEqual(cert.ca, self.ca)
cert.full_clean() # assert e.g. max_length in serials
@@ -53,7 +53,7 @@ def test_der(self) -> None:
self.assertEqual(out, "")
self.assertEqual(err, "")
- cert = Certificate.objects.get(serial=certs["root-cert"]["serial"])
+ cert = Certificate.objects.get(serial=CERT_DATA["root-cert"]["serial"])
self.assertSignature([self.ca], cert)
self.assertEqual(cert.ca, self.ca)
cert.full_clean() # assert e.g. max_length in serials
diff --git a/ca/django_ca/tests/commands/test_init_ca.py b/ca/django_ca/tests/commands/test_init_ca.py
index 20854f6ee..9a34481d5 100644
--- a/ca/django_ca/tests/commands/test_init_ca.py
+++ b/ca/django_ca/tests/commands/test_init_ca.py
@@ -36,7 +36,7 @@
from django_ca import ca_settings
from django_ca.constants import ExtendedKeyUsageOID
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import dns, override_tmpcadir, timestamps, uri
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
authority_information_access,
@@ -44,12 +44,15 @@
certificate_policies,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
issuer_alternative_name,
key_usage,
name_constraints,
ocsp_no_check,
+ override_tmpcadir,
subject_alternative_name,
+ uri,
)
from django_ca.utils import get_crl_cache_key, int_to_hex, x509_name
@@ -95,7 +98,7 @@ def init_ca_e2e(
return ca
@override_tmpcadir(CA_MIN_KEY_SIZE=1024)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_basic(self) -> None:
"""Basic tests for the command."""
name = "test_basic"
@@ -1040,7 +1043,7 @@ def test_password(self) -> None:
self.assertEqual(key.key_size, 1024)
@override_tmpcadir(CA_MIN_KEY_SIZE=1024)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_default_hostname(self) -> None:
"""Test manually passing a default hostname.
diff --git a/ca/django_ca/tests/commands/test_list_cas.py b/ca/django_ca/tests/commands/test_list_cas.py
index 34a83e1bd..8b2cfb9d8 100644
--- a/ca/django_ca/tests/commands/test_list_cas.py
+++ b/ca/django_ca/tests/commands/test_list_cas.py
@@ -22,7 +22,7 @@
from freezegun import freeze_time
from django_ca.models import CertificateAuthority
-from django_ca.tests.base import certs, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
EXPECTED = """{dsa[serial_colons]} - {dsa[name]}{dsa_state}
@@ -44,49 +44,49 @@ def assertOutput( # pylint: disable=invalid-name
self, output: str, expected: str, **context: Any
) -> None:
"""Assert the output of this command."""
- context.update(certs)
+ context.update(CERT_DATA)
for ca_name in self.cas:
context.setdefault(f"{ca_name}_state", "")
self.assertEqual(output, expected.format(**context))
def test_all_cas(self) -> None:
"""Test list with all CAs."""
- for name in [k for k, v in certs.items() if v.get("type") == "ca" and k not in self.cas]:
+ for name in [k for k, v in CERT_DATA.items() if v.get("type") == "ca" and k not in self.cas]:
self.load_ca(name)
stdout, stderr = self.cmd("list_cas")
self.assertEqual(
stdout,
- f"""{certs['letsencrypt_x1']['serial_colons']} - {certs['letsencrypt_x1']['name']}
-{certs['letsencrypt_x3']['serial_colons']} - {certs['letsencrypt_x3']['name']}
-{certs['dst_root_x3']['serial_colons']} - {certs['dst_root_x3']['name']}
-{certs['google_g3']['serial_colons']} - {certs['google_g3']['name']}
-{certs['globalsign_r2_root']['serial_colons']} - {certs['globalsign_r2_root']['name']}
-{certs['trustid_server_a52']['serial_colons']} - {certs['trustid_server_a52']['name']}
-{certs['rapidssl_g3']['serial_colons']} - {certs['rapidssl_g3']['name']}
-{certs['geotrust']['serial_colons']} - {certs['geotrust']['name']}
-{certs['startssl_class2']['serial_colons']} - {certs['startssl_class2']['name']}
-{certs['digicert_sha2']['serial_colons']} - {certs['digicert_sha2']['name']}
-{certs['dsa']['serial_colons']} - {certs['dsa']['name']}
-{certs['ec']['serial_colons']} - {certs['ec']['name']}
-{certs['ed25519']['serial_colons']} - {certs['ed25519']['name']}
-{certs['ed448']['serial_colons']} - {certs['ed448']['name']}
-{certs['pwd']['serial_colons']} - {certs['pwd']['name']}
-{certs['root']['serial_colons']} - {certs['root']['name']}
-{certs['child']['serial_colons']} - {certs['child']['name']}
-{certs['globalsign_dv']['serial_colons']} - {certs['globalsign_dv']['name']}
-{certs['comodo_ev']['serial_colons']} - {certs['comodo_ev']['name']}
-{certs['globalsign']['serial_colons']} - {certs['globalsign']['name']}
-{certs['digicert_ha_intermediate']['serial_colons']} - {certs['digicert_ha_intermediate']['name']}
-{certs['comodo_dv']['serial_colons']} - {certs['comodo_dv']['name']}
-{certs['startssl_class3']['serial_colons']} - {certs['startssl_class3']['name']}
-{certs['godaddy_g2_intermediate']['serial_colons']} - {certs['godaddy_g2_intermediate']['name']}
-{certs['digicert_ev_root']['serial_colons']} - {certs['digicert_ev_root']['name']}
-{certs['digicert_global_root']['serial_colons']} - {certs['digicert_global_root']['name']}
-{certs['identrust_root_1']['serial_colons']} - {certs['identrust_root_1']['name']}
-{certs['startssl_root']['serial_colons']} - {certs['startssl_root']['name']}
-{certs['godaddy_g2_root']['serial_colons']} - {certs['godaddy_g2_root']['name']}
-{certs['comodo']['serial_colons']} - {certs['comodo']['name']}
+ f"""{CERT_DATA['letsencrypt_x1']['serial_colons']} - {CERT_DATA['letsencrypt_x1']['name']}
+{CERT_DATA['letsencrypt_x3']['serial_colons']} - {CERT_DATA['letsencrypt_x3']['name']}
+{CERT_DATA['dst_root_x3']['serial_colons']} - {CERT_DATA['dst_root_x3']['name']}
+{CERT_DATA['google_g3']['serial_colons']} - {CERT_DATA['google_g3']['name']}
+{CERT_DATA['globalsign_r2_root']['serial_colons']} - {CERT_DATA['globalsign_r2_root']['name']}
+{CERT_DATA['trustid_server_a52']['serial_colons']} - {CERT_DATA['trustid_server_a52']['name']}
+{CERT_DATA['rapidssl_g3']['serial_colons']} - {CERT_DATA['rapidssl_g3']['name']}
+{CERT_DATA['geotrust']['serial_colons']} - {CERT_DATA['geotrust']['name']}
+{CERT_DATA['startssl_class2']['serial_colons']} - {CERT_DATA['startssl_class2']['name']}
+{CERT_DATA['digicert_sha2']['serial_colons']} - {CERT_DATA['digicert_sha2']['name']}
+{CERT_DATA['dsa']['serial_colons']} - {CERT_DATA['dsa']['name']}
+{CERT_DATA['ec']['serial_colons']} - {CERT_DATA['ec']['name']}
+{CERT_DATA['ed25519']['serial_colons']} - {CERT_DATA['ed25519']['name']}
+{CERT_DATA['ed448']['serial_colons']} - {CERT_DATA['ed448']['name']}
+{CERT_DATA['pwd']['serial_colons']} - {CERT_DATA['pwd']['name']}
+{CERT_DATA['root']['serial_colons']} - {CERT_DATA['root']['name']}
+{CERT_DATA['child']['serial_colons']} - {CERT_DATA['child']['name']}
+{CERT_DATA['globalsign_dv']['serial_colons']} - {CERT_DATA['globalsign_dv']['name']}
+{CERT_DATA['comodo_ev']['serial_colons']} - {CERT_DATA['comodo_ev']['name']}
+{CERT_DATA['globalsign']['serial_colons']} - {CERT_DATA['globalsign']['name']}
+{CERT_DATA['digicert_ha_intermediate']['serial_colons']} - {CERT_DATA['digicert_ha_intermediate']['name']}
+{CERT_DATA['comodo_dv']['serial_colons']} - {CERT_DATA['comodo_dv']['name']}
+{CERT_DATA['startssl_class3']['serial_colons']} - {CERT_DATA['startssl_class3']['name']}
+{CERT_DATA['godaddy_g2_intermediate']['serial_colons']} - {CERT_DATA['godaddy_g2_intermediate']['name']}
+{CERT_DATA['digicert_ev_root']['serial_colons']} - {CERT_DATA['digicert_ev_root']['name']}
+{CERT_DATA['digicert_global_root']['serial_colons']} - {CERT_DATA['digicert_global_root']['name']}
+{CERT_DATA['identrust_root_1']['serial_colons']} - {CERT_DATA['identrust_root_1']['name']}
+{CERT_DATA['startssl_root']['serial_colons']} - {CERT_DATA['startssl_root']['name']}
+{CERT_DATA['godaddy_g2_root']['serial_colons']} - {CERT_DATA['godaddy_g2_root']['name']}
+{CERT_DATA['comodo']['serial_colons']} - {CERT_DATA['comodo']['name']}
""",
)
self.assertEqual(stderr, "")
@@ -113,7 +113,7 @@ def test_disabled(self) -> None:
self.assertOutput(stdout, EXPECTED, child_state=" (disabled)")
self.assertEqual(stderr, "")
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_tree(self) -> None:
"""Test the tree output.
@@ -122,13 +122,13 @@ def test_tree(self) -> None:
stdout, stderr = self.cmd("list_cas", tree=True)
self.assertEqual(
stdout,
- f"""{certs['dsa']['serial_colons']} - {certs['dsa']['name']}
-{certs['ec']['serial_colons']} - {certs['ec']['name']}
-{certs['ed25519']['serial_colons']} - {certs['ed25519']['name']}
-{certs['ed448']['serial_colons']} - {certs['ed448']['name']}
-{certs['pwd']['serial_colons']} - {certs['pwd']['name']}
-{certs['root']['serial_colons']} - {certs['root']['name']}
-└───{certs['child']['serial_colons']} - {certs['child']['name']}
+ f"""{CERT_DATA['dsa']['serial_colons']} - {CERT_DATA['dsa']['name']}
+{CERT_DATA['ec']['serial_colons']} - {CERT_DATA['ec']['name']}
+{CERT_DATA['ed25519']['serial_colons']} - {CERT_DATA['ed25519']['name']}
+{CERT_DATA['ed448']['serial_colons']} - {CERT_DATA['ed448']['name']}
+{CERT_DATA['pwd']['serial_colons']} - {CERT_DATA['pwd']['name']}
+{CERT_DATA['root']['serial_colons']} - {CERT_DATA['root']['name']}
+└───{CERT_DATA['child']['serial_colons']} - {CERT_DATA['child']['name']}
""",
)
self.assertEqual(stderr, "")
@@ -137,7 +137,7 @@ def test_tree(self) -> None:
expires = timezone.now() + timedelta(days=3)
valid_from = timezone.now() - timedelta(days=3)
root = self.cas["root"]
- pub = certs["child-cert"]["pub"]["parsed"]
+ pub = CERT_DATA["child-cert"]["pub"]["parsed"]
child3 = CertificateAuthority.objects.create(
name="child3", serial="child3", parent=root, expires=expires, valid_from=valid_from, pub=pub
)
@@ -151,15 +151,15 @@ def test_tree(self) -> None:
stdout, stderr = self.cmd("list_cas", tree=True)
self.assertEqual(
stdout,
- f"""{certs['dsa']['serial_colons']} - {certs['dsa']['name']}
-{certs['ec']['serial_colons']} - {certs['ec']['name']}
-{certs['ed25519']['serial_colons']} - {certs['ed25519']['name']}
-{certs['ed448']['serial_colons']} - {certs['ed448']['name']}
-{certs['pwd']['serial_colons']} - {certs['pwd']['name']}
-{certs['root']['serial_colons']} - {certs['root']['name']}
+ f"""{CERT_DATA['dsa']['serial_colons']} - {CERT_DATA['dsa']['name']}
+{CERT_DATA['ec']['serial_colons']} - {CERT_DATA['ec']['name']}
+{CERT_DATA['ed25519']['serial_colons']} - {CERT_DATA['ed25519']['name']}
+{CERT_DATA['ed448']['serial_colons']} - {CERT_DATA['ed448']['name']}
+{CERT_DATA['pwd']['serial_colons']} - {CERT_DATA['pwd']['name']}
+{CERT_DATA['root']['serial_colons']} - {CERT_DATA['root']['name']}
│───ch:il:d3 - child3
│ └───ch:il:d3:.1 - child3.1
│───ch:il:d4 - child4
-└───{certs['child']['serial_colons']} - {certs['child']['name']}
+└───{CERT_DATA['child']['serial_colons']} - {CERT_DATA['child']['name']}
""",
)
diff --git a/ca/django_ca/tests/commands/test_list_certs.py b/ca/django_ca/tests/commands/test_list_certs.py
index 1a894a2f2..236c94787 100644
--- a/ca/django_ca/tests/commands/test_list_certs.py
+++ b/ca/django_ca/tests/commands/test_list_certs.py
@@ -21,7 +21,7 @@
from freezegun import freeze_time
from django_ca.models import Certificate
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.utils import add_colons
@@ -51,18 +51,18 @@ def assertCerts(self, *certs: Certificate, **kwargs: Any) -> None: # pylint: di
self.assertEqual(stdout, "".join([f"{self._line(c)}\n" for c in sorted_certs]))
self.assertEqual(stderr, "")
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_basic(self) -> None:
"""Basic test."""
self.assertCerts(*self.certs.values())
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_expired(self) -> None:
"""Test listing of expired certs."""
self.assertCerts()
self.assertCerts(*self.certs.values(), expired=True)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_revoked(self) -> None:
"""Test listing of revoked certs."""
cert = self.certs["root-cert"]
@@ -71,7 +71,7 @@ def test_revoked(self) -> None:
self.assertCerts(*[c for c in self.certs.values() if c != cert])
self.assertCerts(*self.certs.values(), revoked=True)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_autogenerated(self) -> None:
"""Test listing of autogenerated certs."""
cert = self.certs["root-cert"]
@@ -81,7 +81,7 @@ def test_autogenerated(self) -> None:
self.assertCerts(*[c for c in self.certs.values() if c != cert])
self.assertCerts(*self.certs.values(), autogenerated=True)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_ca(self) -> None:
"""Test listing for all CAs."""
for ca in self.cas.values():
diff --git a/ca/django_ca/tests/commands/test_notify.py b/ca/django_ca/tests/commands/test_notify.py
index dbe277b8b..eb0573693 100644
--- a/ca/django_ca/tests/commands/test_notify.py
+++ b/ca/django_ca/tests/commands/test_notify.py
@@ -21,7 +21,7 @@
from freezegun import freeze_time
from django_ca.models import Watcher
-from django_ca.tests.base import timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
@@ -32,7 +32,7 @@ class NotifyExpiringCertsTestCase(TestCaseMixin, TestCase):
load_cas = "__usable__"
load_certs = "__usable__"
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_no_certs(self) -> None:
"""Try notify command when all certs are still valid."""
stdout, stderr = self.cmd("notify_expiring_certs")
@@ -40,7 +40,7 @@ def test_no_certs(self) -> None:
self.assertEqual(stderr, "")
self.assertEqual(len(mail.outbox), 0)
- @freeze_time(timestamps["ca_certs_expiring"])
+ @freeze_time(TIMESTAMPS["ca_certs_expiring"])
def test_no_watchers(self) -> None:
"""Try expiring certs, but with no watchers."""
# certs have no watchers by default, so we get no mails
@@ -49,7 +49,7 @@ def test_no_watchers(self) -> None:
self.assertEqual(stderr, "")
self.assertEqual(len(mail.outbox), 0)
- @freeze_time(timestamps["ca_certs_expiring"])
+ @freeze_time(TIMESTAMPS["ca_certs_expiring"])
def test_one_watcher(self) -> None:
"""Test one expiring certificate."""
email = "user1@example.com"
diff --git a/ca/django_ca/tests/commands/test_regenerate_ocsp_keys.py b/ca/django_ca/tests/commands/test_regenerate_ocsp_keys.py
index a32c6dfda..1d257cc7e 100644
--- a/ca/django_ca/tests/commands/test_regenerate_ocsp_keys.py
+++ b/ca/django_ca/tests/commands/test_regenerate_ocsp_keys.py
@@ -25,9 +25,9 @@
from django.test import TestCase
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import certs, override_tmpcadir, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
-from django_ca.tests.base.utils import authority_information_access
+from django_ca.tests.base.utils import authority_information_access, override_tmpcadir, uri
from django_ca.utils import add_colons, ca_storage
@@ -100,7 +100,7 @@ def assertHasNoKey(self, serial: str) -> None: # pylint: disable=invalid-name
def test_basic(self) -> None:
"""Basic test."""
with self.mute_celery():
- stdout, stderr = self.cmd("regenerate_ocsp_keys", certs["root"]["serial"])
+ stdout, stderr = self.cmd("regenerate_ocsp_keys", CERT_DATA["root"]["serial"])
self.assertEqual(stdout, "")
self.assertEqual(stderr, "")
@@ -111,7 +111,7 @@ def test_rsa_with_key_size(self) -> None:
"""Test creating an RSA key with explicit key size."""
with self.mute_celery():
stdout, stderr = self.cmd(
- "regenerate_ocsp_keys", certs["root"]["serial"], key_type="RSA", key_size=4096
+ "regenerate_ocsp_keys", CERT_DATA["root"]["serial"], key_type="RSA", key_size=4096
)
self.assertEqual(stdout, "")
@@ -123,7 +123,7 @@ def test_ec_with_curve(self) -> None:
"""Test creating an EC key with explicit elliptic curve."""
with self.mute_celery():
stdout, stderr = self.cmd(
- "regenerate_ocsp_keys", certs["ec"]["serial"], elliptic_curve=ec.SECP384R1()
+ "regenerate_ocsp_keys", CERT_DATA["ec"]["serial"], elliptic_curve=ec.SECP384R1()
)
self.assertEqual(stdout, "")
@@ -135,7 +135,7 @@ def test_hash_algorithm(self) -> None:
"""Test the hash algorithm option."""
with self.mute_celery():
stdout, stderr = self.cmd(
- "regenerate_ocsp_keys", certs["root"]["serial"], "--algorithm", "SHA-256"
+ "regenerate_ocsp_keys", CERT_DATA["root"]["serial"], "--algorithm", "SHA-256"
)
self.assertEqual(stdout, "")
@@ -148,7 +148,7 @@ def test_with_celery(self) -> None:
with self.mute_celery(
(
(
- (certs["root"]["serial"],),
+ (CERT_DATA["root"]["serial"],),
{
"profile": "ocsp",
"expires": 172800.0,
@@ -164,7 +164,7 @@ def test_with_celery(self) -> None:
),
):
stdout, stderr = self.cmd_e2e(
- ["regenerate_ocsp_keys", certs["root"]["serial"], "--algorithm", "SHA-256"]
+ ["regenerate_ocsp_keys", CERT_DATA["root"]["serial"], "--algorithm", "SHA-256"]
)
self.assertEqual(stdout, "")
self.assertEqual(stderr, "")
@@ -173,7 +173,7 @@ def test_with_celery(self) -> None:
def test_with_ed448_with_explicit_key_type(self) -> None:
"""Test creating an Ed448-based OCSP key for an RSA-based CA."""
stdout, stderr = self.cmd_e2e(
- ["regenerate_ocsp_keys", certs["root"]["serial"], "--key-type", "Ed448"]
+ ["regenerate_ocsp_keys", CERT_DATA["root"]["serial"], "--key-type", "Ed448"]
)
self.assertEqual(stdout, "")
self.assertEqual(stderr, "")
@@ -196,7 +196,7 @@ def test_all(self) -> None:
@override_tmpcadir()
def test_overwrite(self) -> None:
"""Test overwriting pre-generated OCSP keys."""
- stdout, stderr = self.cmd("regenerate_ocsp_keys", certs["root"]["serial"])
+ stdout, stderr = self.cmd("regenerate_ocsp_keys", CERT_DATA["root"]["serial"])
self.assertEqual(stdout, "")
self.assertEqual(stderr, "")
priv, cert = self.assertKey(self.cas["root"])
@@ -205,7 +205,7 @@ def test_overwrite(self) -> None:
excludes = list(Certificate.objects.all().values_list("pk", flat=True))
# write again
- stdout, stderr = self.cmd("regenerate_ocsp_keys", certs["root"]["serial"], force=True)
+ stdout, stderr = self.cmd("regenerate_ocsp_keys", CERT_DATA["root"]["serial"], force=True)
self.assertEqual(stdout, "")
self.assertEqual(stderr, "")
new_priv, new_cert = self.assertKey(self.cas["root"], excludes=excludes)
@@ -227,8 +227,8 @@ def test_wrong_serial(self) -> None:
def test_no_ocsp_profile(self) -> None:
"""Try when there is no OCSP profile."""
with self.assertCommandError(r"^ocsp: Undefined profile\.$"):
- self.cmd("regenerate_ocsp_keys", certs["root"]["serial"])
- self.assertHasNoKey(certs["root"]["serial"])
+ self.cmd("regenerate_ocsp_keys", CERT_DATA["root"]["serial"])
+ self.assertHasNoKey(CERT_DATA["root"]["serial"])
@override_tmpcadir()
def test_no_private_key(self) -> None:
diff --git a/ca/django_ca/tests/commands/test_resign_cert.py b/ca/django_ca/tests/commands/test_resign_cert.py
index 5b06ef100..1fdfd5625 100644
--- a/ca/django_ca/tests/commands/test_resign_cert.py
+++ b/ca/django_ca/tests/commands/test_resign_cert.py
@@ -29,23 +29,26 @@
from django_ca import ca_settings
from django_ca.models import Certificate, CertificateAuthority, Watcher
-from django_ca.tests.base import dns, override_tmpcadir, timestamps, uri
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
basic_constraints,
certificate_policies,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
issuer_alternative_name,
key_usage,
ocsp_no_check,
+ override_tmpcadir,
subject_alternative_name,
tls_feature,
+ uri,
)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class ResignCertTestCase(TestCaseMixin, TestCase):
"""Main test class for this command."""
diff --git a/ca/django_ca/tests/commands/test_sign_cert.py b/ca/django_ca/tests/commands/test_sign_cert.py
index 636df5863..23b6900d7 100644
--- a/ca/django_ca/tests/commands/test_sign_cert.py
+++ b/ca/django_ca/tests/commands/test_sign_cert.py
@@ -34,25 +34,28 @@
from django_ca import ca_settings
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import certs, dns, override_tmpcadir, timestamps, uri
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
authority_information_access,
certificate_policies,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
issuer_alternative_name,
key_usage,
ocsp_no_check,
+ override_tmpcadir,
subject_alternative_name,
tls_feature,
+ uri,
)
from django_ca.utils import ca_storage
@override_settings(CA_MIN_KEY_SIZE=1024, CA_PROFILES={}, CA_DEFAULT_SUBJECT=tuple())
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class SignCertTestCase(TestCaseMixin, TestCase): # pylint: disable=too-many-public-methods
"""Main test class for this command."""
@@ -61,7 +64,7 @@ class SignCertTestCase(TestCaseMixin, TestCase): # pylint: disable=too-many-pub
def setUp(self) -> None:
super().setUp()
- self.csr_pem = certs["root-cert"]["csr"]["pem"]
+ self.csr_pem = CERT_DATA["root-cert"]["csr"]["pem"]
@override_tmpcadir()
def test_from_stdin(self) -> None:
@@ -104,9 +107,9 @@ def test_with_bundle(self) -> None:
def test_usable_cas(self) -> None:
"""Test signing with all usable CAs."""
for name, ca in self.cas.items():
- stdin = certs[f"{name}-cert"]["csr"]["pem"].encode()
+ stdin = CERT_DATA[f"{name}-cert"]["csr"]["pem"].encode()
- password = certs[name].get("password")
+ password = CERT_DATA[name].get("password")
with self.assertCreateCertSignals() as (pre, post):
stdout, stderr = self.cmd(
@@ -707,7 +710,7 @@ def test_der_csr(self) -> None:
"""Test using a DER CSR."""
csr_path = os.path.join(ca_settings.CA_DIR, "test.csr")
with open(csr_path, "wb") as csr_stream:
- csr_stream.write(certs["child-cert"]["csr"]["parsed"].public_bytes(Encoding.DER))
+ csr_stream.write(CERT_DATA["child-cert"]["csr"]["parsed"].public_bytes(Encoding.DER))
with self.assertCreateCertSignals() as (pre, post):
stdout, stderr = self.cmd("sign_cert", ca=self.ca, subject=self.subject, csr=csr_path)
@@ -781,7 +784,7 @@ def test_unusable_ca(self) -> None:
self.cmd("sign_cert", ca=self.ca, subject=self.subject, stdin=stdin)
@override_tmpcadir()
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_ca(self) -> None:
"""Test signing with an expired CA."""
stdin = io.StringIO(self.csr_pem)
diff --git a/ca/django_ca/tests/commands/test_view_ca.py b/ca/django_ca/tests/commands/test_view_ca.py
index 5a42e09a0..89c01c832 100644
--- a/ca/django_ca/tests/commands/test_view_ca.py
+++ b/ca/django_ca/tests/commands/test_view_ca.py
@@ -22,8 +22,8 @@
from django.conf import settings
from django.test import TestCase
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
expected = {
"ec": """* Name: {name}
diff --git a/ca/django_ca/tests/commands/test_view_cert.py b/ca/django_ca/tests/commands/test_view_cert.py
index c94821446..e42a3575a 100644
--- a/ca/django_ca/tests/commands/test_view_cert.py
+++ b/ca/django_ca/tests/commands/test_view_cert.py
@@ -24,8 +24,9 @@
from freezegun import freeze_time
from django_ca.models import Watcher
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
expected = {
"root-cert": """* Subject: {subject_str}
@@ -583,17 +584,17 @@ def assertBasicOutput(self, status: str) -> None: # pylint: disable=invalid-nam
)
self.assertEqual(stderr, "")
- @freeze_time(timestamps["before_everything"])
+ @freeze_time(TIMESTAMPS["before_everything"])
def test_basic_not_yet_valid(self) -> None:
"""Basic tests when all certs are not yet valid."""
self.assertBasicOutput(status="Not yet valid")
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_basic_expired(self) -> None:
"""Basic tests when all certs are expired."""
self.assertBasicOutput(status="Expired")
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_certs(self) -> None:
"""Test main certs."""
for name, cert in self.usable_certs:
@@ -623,12 +624,12 @@ def test_revoked(self) -> None:
SHA-256: {sha256}
SHA-512: {sha512}
""".format(
- **certs["child-cert"]
+ **CERT_DATA["child-cert"]
),
)
self.assertEqual(stderr, "")
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
@override_tmpcadir()
def test_no_san_with_watchers(self) -> None:
"""Test a cert with no subjectAltNames but with watchers."""
@@ -733,13 +734,13 @@ def test_contrib_letsencrypt_jabber_at(self) -> None:
context[
"id2"
] = "29:3C:51:96:54:C8:39:65:BA:AA:50:FC:58:07:D4:B7:6F:BF:58:7A:29:72:DC:A4:C3:0C:F4:E5:45:47:F4:78" # NOQA: E501
- sct = """* Precertificate Signed Certificate Timestamps{sct_critical}:
- * Precertificate ({sct_values[0][version]}):
- Timestamp: {sct_values[0][timestamp]}
+ sct = """* Precertificate Signed Certificate Timestamps{precertificate_signed_certificate_timestamps_critical}:
+ * Precertificate ({precertificate_signed_certificate_timestamps_serialized[0][version]}):
+ Timestamp: {precertificate_signed_certificate_timestamps_serialized[0][timestamp]}
Log ID: {id1}
- * Precertificate ({sct_values[1][version]}):
- Timestamp: {sct_values[1][timestamp]}
- Log ID: {id2}""".format(
+ * Precertificate ({precertificate_signed_certificate_timestamps_serialized[1][version]}):
+ Timestamp: {precertificate_signed_certificate_timestamps_serialized[1][timestamp]}
+ Log ID: {id2}""".format( # NOQA: E501
**context
)
diff --git a/ca/django_ca/tests/conftest.py b/ca/django_ca/tests/conftest.py
index 1fdde9d0d..61d1fc5ab 100644
--- a/ca/django_ca/tests/conftest.py
+++ b/ca/django_ca/tests/conftest.py
@@ -34,7 +34,6 @@
from django_ca.models import Certificate
from django_ca.profiles import profiles
-from django_ca.tests.base import GECKODRIVER_PATH, RUN_SELENIUM_TESTS
from django_ca.tests.base.conftest_helpers import (
generate_ca_fixture,
generate_cert_fixture,
@@ -45,6 +44,7 @@
usable_ca_names,
usable_cert_names,
)
+from django_ca.tests.base.constants import GECKODRIVER_PATH, RUN_SELENIUM_TESTS
from django_ca.tests.base.typehints import User
from django_ca.utils import ca_storage
diff --git a/ca/django_ca/tests/extensions/test_admin_html.py b/ca/django_ca/tests/extensions/test_admin_html.py
index f81ed504d..d2faaf295 100644
--- a/ca/django_ca/tests/extensions/test_admin_html.py
+++ b/ca/django_ca/tests/extensions/test_admin_html.py
@@ -24,7 +24,7 @@
from django_ca.constants import KEY_USAGE_NAMES
from django_ca.extensions.utils import extension_as_admin_html
from django_ca.models import X509CertMixin
-from django_ca.tests.base import certs
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
@@ -36,23 +36,23 @@ class CertificateExtensionTestCase(TestCaseMixin, TestCase):
admin_html: Dict[str, Dict[x509.ObjectIdentifier, str]] = {
"root": {},
"child": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['child']['path_length']}",
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['child']['path_length']}",
},
"ec": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['ec']['path_length']}",
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['ec']['path_length']}",
},
"dsa": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['dsa']['path_length']}",
- ExtensionOID.SUBJECT_KEY_IDENTIFIER: certs["dsa"]["subject_key_identifier_serialized"]["value"],
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['dsa']['path_length']}",
+ ExtensionOID.SUBJECT_KEY_IDENTIFIER: CERT_DATA["dsa"]["subject_key_identifier_serialized"],
},
"pwd": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['pwd']['path_length']}",
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['pwd']['path_length']}",
},
"ed25519": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['ed25519']['path_length']}",
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['ed25519']['path_length']}",
},
"ed448": {
- ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {certs['ed448']['path_length']}",
+ ExtensionOID.BASIC_CONSTRAINTS: f"CA: True, path length: {CERT_DATA['ed448']['path_length']}",
},
"trustid_server_a52": {
ExtensionOID.CERTIFICATE_POLICIES: """
@@ -228,7 +228,7 @@ class CertificateExtensionTestCase(TestCaseMixin, TestCase):
##########################
"all-extensions": {
ExtensionOID.FRESHEST_CRL: f"""DistributionPoint:
- - Full Name: {certs['all-extensions']['freshest_crl_serialized']['value'][0]['full_name'][0]}
+ - Full Name: {CERT_DATA['all-extensions']['freshest_crl_serialized'][0]['full_name'][0]}
""", # NOQA: E501
ExtensionOID.INHIBIT_ANY_POLICY: "skip certs: 1",
ExtensionOID.NAME_CONSTRAINTS: """Permitted:
@@ -606,32 +606,30 @@ def setUpCert(self, name: str) -> None: # pylint: disable=invalid-name
"""Set up default values for certificates."""
self.admin_html.setdefault(name, {})
- config = certs[name]
+ config = CERT_DATA[name]
if config.get("subject_alternative_name_serialized"):
- sans = [f"- {san}
" for san in config["subject_alternative_name_serialized"]["value"]]
+ sans = [f"- {san}
" for san in config["subject_alternative_name_serialized"]]
self.admin_html[name].setdefault(
ExtensionOID.SUBJECT_ALTERNATIVE_NAME, f""
)
if config.get("issuer_alternative_name_serialized"):
- sans = [f"- {san}
" for san in config["issuer_alternative_name_serialized"]["value"]]
+ sans = [f"- {san}
" for san in config["issuer_alternative_name_serialized"]]
self.admin_html[name].setdefault(
ExtensionOID.ISSUER_ALTERNATIVE_NAME, f""
)
if config.get("key_usage_serialized"):
- kus = sorted(
- [f"- {KEY_USAGE_NAMES[ku]}
" for ku in config["key_usage_serialized"]["value"]]
- )
+ kus = sorted([f"- {KEY_USAGE_NAMES[ku]}
" for ku in config["key_usage_serialized"]])
self.admin_html[name].setdefault(ExtensionOID.KEY_USAGE, f"")
# NOTE: Custom extension class sorts values, but we render them in order as they appear in the
# certificate, so we still have to override this in some places.
if config.get("extended_key_usage_serialized"):
- ekus = [f"- {eku}
" for eku in config["extended_key_usage_serialized"]["value"]]
+ ekus = [f"- {eku}
" for eku in config["extended_key_usage_serialized"]]
self.admin_html[name].setdefault(ExtensionOID.EXTENDED_KEY_USAGE, f"")
if config.get("crl_distribution_points_serialized"):
- ext_config = config["crl_distribution_points_serialized"]["value"]
+ ext_config = config["crl_distribution_points_serialized"]
full_names = []
for dpoint in ext_config:
@@ -649,24 +647,23 @@ def setUpCert(self, name: str) -> None: # pylint: disable=invalid-name
),
)
- if certs[name].get("subject_key_identifier_serialized"):
+ if CERT_DATA[name].get("subject_key_identifier_serialized"):
self.admin_html[name].setdefault(
ExtensionOID.SUBJECT_KEY_IDENTIFIER,
- certs[name]["subject_key_identifier_serialized"]["value"],
+ CERT_DATA[name]["subject_key_identifier_serialized"],
)
- if certs[name].get("ocsp_no_check_serialized"):
+ if CERT_DATA[name].get("ocsp_no_check"):
self.admin_html[name].setdefault(ExtensionOID.OCSP_NO_CHECK, "Yes")
- aki = certs[name].get("authority_key_identifier_serialized", {}).get("value", {})
+ aki = CERT_DATA[name].get("authority_key_identifier_serialized", {})
if isinstance(aki, dict) and aki.get("key_identifier"):
self.admin_html[name].setdefault(
ExtensionOID.AUTHORITY_KEY_IDENTIFIER,
f"- Key ID: {aki['key_identifier']}
",
)
- aia = certs[name].get("authority_information_access_serialized", {}).get("value", {})
- if aia:
+ if aia := CERT_DATA[name].get("authority_information_access_serialized", {}):
lines = []
if "issuers" in aia:
issuers = [f"- {fn}
" for fn in aia["issuers"]]
@@ -690,11 +687,10 @@ def setUp(self) -> None:
def assertAdminHTML(self, name: str, cert: X509CertMixin) -> None: # pylint: disable=invalid-name
"""Assert that the actual extension HTML is equivalent to the expected HTML."""
for oid, ext in cert.x509_extensions.items():
- self.assertIn(oid, self.admin_html[name], name)
+ self.assertIn(oid, self.admin_html[name], (name, oid))
admin_html = self.admin_html[name][oid]
admin_html = f'\n{admin_html}
'
actual = extension_as_admin_html(ext)
-
msg_prefix = f"{name}, {oid}: actual:\n{actual}\n"
self.assertInHTML(admin_html, mark_safe(actual), msg_prefix=msg_prefix)
diff --git a/ca/django_ca/tests/extensions/test_extension_values.py b/ca/django_ca/tests/extensions/test_extension_values.py
index 0ebdcf5e9..6d5b5e7dc 100644
--- a/ca/django_ca/tests/extensions/test_extension_values.py
+++ b/ca/django_ca/tests/extensions/test_extension_values.py
@@ -26,8 +26,9 @@
from django_ca.constants import EXTENSION_DEFAULT_CRITICAL, ExtendedKeyUsageOID
from django_ca.extensions import extension_as_text, parse_extension, serialize_extension
from django_ca.extensions.utils import extension_as_admin_html
-from django_ca.tests.base import certs, dns, rdn, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin, TestCaseProtocol
+from django_ca.tests.base.utils import dns, rdn, uri
from django_ca.typehints import CRLExtensionType, ParsableDistributionPoint, ParsablePolicyInformation
_ExtensionExampleDict = typing.TypedDict(
@@ -1132,8 +1133,8 @@ def test_serialize(self) -> None:
"""Test serialization."""
for key in self.load_certs:
self.assertEqual(
- serialize_extension(self.certs[key].x509_extensions[self.oid]),
- certs[key]["precertificate_signed_certificate_timestamps"],
+ serialize_extension(self.certs[key].x509_extensions[self.oid])["value"],
+ CERT_DATA[key]["precertificate_signed_certificate_timestamps_serialized"],
)
def test_parse(self) -> None:
diff --git a/ca/django_ca/tests/test_admin_acme.py b/ca/django_ca/tests/test_admin_acme.py
index 02e0ebb38..1a50b8ad6 100644
--- a/ca/django_ca/tests/test_admin_acme.py
+++ b/ca/django_ca/tests/test_admin_acme.py
@@ -27,10 +27,10 @@
AcmeOrder,
CertificateAuthority,
)
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.assertions import assert_changelist_response
from django_ca.tests.base.mixins import StandardAdminViewTestCaseMixin
from django_ca.tests.base.typehints import DjangoCAModelTypeVar
+from django_ca.tests.base.utils import override_tmpcadir
PEM1 = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvP5N/1KjBQniyyukn30E
diff --git a/ca/django_ca/tests/test_base.py b/ca/django_ca/tests/test_base.py
index 432e4f187..2839cb996 100644
--- a/ca/django_ca/tests/test_base.py
+++ b/ca/django_ca/tests/test_base.py
@@ -23,8 +23,8 @@
from django.test import TestCase, override_settings
from django_ca import ca_settings
-from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir
from django_ca.utils import add_colons
diff --git a/ca/django_ca/tests/test_docs.py b/ca/django_ca/tests/test_docs.py
index 1703c209a..21357f970 100644
--- a/ca/django_ca/tests/test_docs.py
+++ b/ca/django_ca/tests/test_docs.py
@@ -24,7 +24,8 @@
import pytest
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import DOC_DIR, certs, override_tmpcadir
+from django_ca.tests.base.constants import CERT_DATA, DOC_DIR
+from django_ca.tests.base.utils import override_tmpcadir
BASE = os.path.relpath(DOC_DIR, os.path.dirname(__file__))
@@ -37,7 +38,7 @@ def globs(usable_root: CertificateAuthority, root_cert: Certificate) -> Dict[str
"ca_serial": usable_root.serial,
"cert": root_cert,
"cert_serial": root_cert.serial,
- "csr": certs["root-cert"]["csr"]["parsed"],
+ "csr": CERT_DATA["root-cert"]["csr"]["parsed"],
"x509": x509,
}
diff --git a/ca/django_ca/tests/test_fields.py b/ca/django_ca/tests/test_fields.py
index 5b213cf36..bc220493e 100644
--- a/ca/django_ca/tests/test_fields.py
+++ b/ca/django_ca/tests/test_fields.py
@@ -27,7 +27,6 @@
from django_ca import ca_settings, fields
from django_ca.constants import KEY_USAGE_NAMES, REVOCATION_REASONS
-from django_ca.tests.base import rdn
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
authority_information_access,
@@ -35,6 +34,7 @@
issuer_alternative_name,
key_usage,
ocsp_no_check,
+ rdn,
tls_feature,
)
diff --git a/ca/django_ca/tests/test_management_actions.py b/ca/django_ca/tests/test_management_actions.py
index 63007ab05..9399d2a4c 100644
--- a/ca/django_ca/tests/test_management_actions.py
+++ b/ca/django_ca/tests/test_management_actions.py
@@ -32,9 +32,9 @@
from django_ca.constants import ReasonFlags
from django_ca.management import actions
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import certs, dns, override_tmpcadir, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
-from django_ca.tests.base.utils import key_usage
+from django_ca.tests.base.utils import dns, key_usage, override_tmpcadir, uri
class ParserTestCaseMixin(TestCaseMixin):
@@ -694,12 +694,12 @@ def setUp(self) -> None:
def test_basic(self) -> None:
"""Test basic functionality of action."""
for name, cert in self.certs.items():
- args = self.parser.parse_args([certs[name]["serial"]])
+ args = self.parser.parse_args([CERT_DATA[name]["serial"]])
self.assertEqual(args.cert, cert)
def test_abbreviation(self) -> None:
"""Test using an abbreviation."""
- args = self.parser.parse_args([certs["root-cert"]["serial"][:6]])
+ args = self.parser.parse_args([CERT_DATA["root-cert"]["serial"][:6]])
self.assertEqual(args.cert, self.certs["root-cert"])
def test_missing(self) -> None:
@@ -716,7 +716,7 @@ def test_multiple(self) -> None:
"""Test matching multiple certs with abbreviation."""
# Manually set almost the same serial on second cert
cert = Certificate(ca=self.cas["root"])
- cert.update_certificate(certs["root-cert"]["pub"]["parsed"])
+ cert.update_certificate(CERT_DATA["root-cert"]["pub"]["parsed"])
cert.serial = cert.serial[:-1] + "X"
cert.save()
@@ -743,13 +743,13 @@ def setUp(self) -> None:
def test_basic(self) -> None:
"""Test basic functionality of action."""
for name, ca in self.usable_cas:
- args = self.parser.parse_args([certs[name]["serial"]])
+ args = self.parser.parse_args([CERT_DATA[name]["serial"]])
self.assertEqual(args.ca, ca)
@override_tmpcadir()
def test_abbreviation(self) -> None:
"""Test using an abbreviation."""
- args = self.parser.parse_args([certs["ec"]["serial"][:6]])
+ args = self.parser.parse_args([CERT_DATA["ec"]["serial"][:6]])
self.assertEqual(args.ca, self.cas["ec"])
def test_missing(self) -> None:
@@ -763,7 +763,7 @@ def test_missing(self) -> None:
def test_multiple(self) -> None:
"""Test an abbreviation matching multiple CAs."""
ca2 = CertificateAuthority(name="child-duplicate")
- ca2.update_certificate(certs["child"]["pub"]["parsed"])
+ ca2.update_certificate(CERT_DATA["child"]["pub"]["parsed"])
ca2.serial = ca2.serial[:-1] + "X"
ca2.save()
@@ -809,7 +809,7 @@ def test_private_key_does_not_exists(self) -> None:
@override_tmpcadir()
def test_password(self) -> None:
"""Test that the action works with a password-encrypted CA."""
- args = self.parser.parse_args([certs["pwd"]["serial"]])
+ args = self.parser.parse_args([CERT_DATA["pwd"]["serial"]])
self.assertEqual(args.ca, self.cas["pwd"])
diff --git a/ca/django_ca/tests/test_managers.py b/ca/django_ca/tests/test_managers.py
index 3d01f8d67..17d685362 100644
--- a/ca/django_ca/tests/test_managers.py
+++ b/ca/django_ca/tests/test_managers.py
@@ -30,20 +30,23 @@
from django_ca.models import Certificate, CertificateAuthority
from django_ca.profiles import profiles
from django_ca.querysets import CertificateAuthorityQuerySet, CertificateQuerySet
-from django_ca.tests.base import certs, dns, override_tmpcadir, timestamps, uri
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
authority_information_access,
basic_constraints,
crl_distribution_points,
distribution_point,
+ dns,
extended_key_usage,
key_usage,
name_constraints,
ocsp_no_check,
+ override_tmpcadir,
precert_poison,
subject_alternative_name,
tls_feature,
+ uri,
)
@@ -371,8 +374,8 @@ def test_unknown_extension_type(self) -> None:
self.assertEqual(CertificateAuthority.objects.filter(name=name).count(), 0)
-@override_settings(CA_PROFILES={}, CA_DEFAULT_SUBJECT=tuple(), CA_DEFAULT_CA=certs["child"]["serial"])
-@freeze_time(timestamps["everything_valid"])
+@override_settings(CA_PROFILES={}, CA_DEFAULT_SUBJECT=tuple(), CA_DEFAULT_CA=CERT_DATA["child"]["serial"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class CertificateAuthorityManagerDefaultTestCase(TestCaseMixin, TestCase):
"""Tests for :py:func:`django_ca.managers.CertificateAuthorityManager.default`."""
@@ -393,13 +396,13 @@ def test_disabled(self) -> None:
with self.assertImproperlyConfigured(rf"^CA_DEFAULT_CA: {self.ca.serial} is disabled\.$"):
CertificateAuthority.objects.default()
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_expired(self) -> None:
"""Test that an exception is raised if CA is expired."""
with self.assertImproperlyConfigured(rf"^CA_DEFAULT_CA: {self.ca.serial} is expired\.$"):
CertificateAuthority.objects.default()
- @freeze_time(timestamps["before_everything"])
+ @freeze_time(TIMESTAMPS["before_everything"])
def test_not_yet_valid(self) -> None:
"""Test that an exception is raised if CA is not yet valid."""
with self.assertImproperlyConfigured(rf"^CA_DEFAULT_CA: {self.ca.serial} is not yet valid\.$"):
@@ -413,7 +416,7 @@ def test_default_ca(self) -> None:
self.assertEqual(CertificateAuthority.objects.default(), ca)
@override_settings(CA_DEFAULT_CA="")
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_default_ca_expired(self) -> None:
"""Test that exception is raised if no CA is currently valid."""
with self.assertImproperlyConfigured(r"^No CA is currently usable\.$"):
@@ -430,7 +433,7 @@ def test_unknown_ca_configured(self) -> None:
class CreateCertTestCase(TestCaseMixin, TestCase):
"""Test :py:class:`django_ca.managers.CertificateManager.create_cert` (create a new cert)."""
- csr = certs["root-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["root-cert"]["csr"]["parsed"]
load_cas = ("root",)
@override_tmpcadir(CA_PROFILES={ca_settings.CA_DEFAULT_PROFILE: {"extensions": {}}})
@@ -486,7 +489,7 @@ def test_profile_unsupported_type(self) -> None:
with self.assertCreateCertSignals(False, False), self.assertRaisesRegex(TypeError, msg):
Certificate.objects.create_cert(
self.ca,
- csr=certs["root-cert"]["csr"]["parsed"],
+ csr=CERT_DATA["root-cert"]["csr"]["parsed"],
profile=False, # type: ignore[arg-type] # what we're testing
subject=self.subject,
add_crl_url=False,
diff --git a/ca/django_ca/tests/test_models.py b/ca/django_ca/tests/test_models.py
index ef0eaf8bf..d2df3b9fe 100644
--- a/ca/django_ca/tests/test_models.py
+++ b/ca/django_ca/tests/test_models.py
@@ -58,16 +58,19 @@
Watcher,
X509CertMixin,
)
-from django_ca.tests.base import CERT_PEM_REGEX, certs, dns, override_tmpcadir, timestamps, uri
+from django_ca.tests.base.constants import CERT_DATA, CERT_PEM_REGEX, TIMESTAMPS
from django_ca.tests.base.mixins import AcmeValuesMixin, TestCaseMixin, TestCaseProtocol
from django_ca.tests.base.utils import (
authority_information_access,
basic_constraints,
crl_distribution_points,
distribution_point,
+ dns,
issuer_alternative_name,
+ override_tmpcadir,
subject_alternative_name,
subject_key_identifier,
+ uri,
)
from django_ca.utils import ca_storage, get_crl_cache_key, x509_name
@@ -179,7 +182,7 @@ def test_key(self) -> None:
"""Test access to the private key."""
for name, ca in self.usable_cas:
self.assertTrue(ca.key_exists)
- self.assertIsNotNone(ca.key(certs[name].get("password")))
+ self.assertIsNotNone(ca.key(CERT_DATA[name].get("password")))
# test a second tome to make sure we reload the key
with mock.patch("django_ca.utils.read_file") as patched:
@@ -190,7 +193,7 @@ def test_key(self) -> None:
ca.private_key_path = os.path.join(ca_settings.CA_DIR, ca.private_key_path)
self.assertTrue(ca.key_exists)
- self.assertIsNotNone(ca.key(certs[name].get("password")))
+ self.assertIsNotNone(ca.key(CERT_DATA[name].get("password")))
# Check again - here we have an already loaded key (also: no logging here anymore)
# NOTE: assertLogs() fails if there are *no* log messages, so we cannot test that
@@ -217,21 +220,21 @@ def test_bundle_as_pem(self) -> None:
def test_key_str_password(self) -> None:
"""Test accessing the private key with a string password."""
ca = self.cas["pwd"]
- pwd = certs["pwd"]["password"].decode("utf-8")
+ pwd = CERT_DATA["pwd"]["password"].decode("utf-8")
self.assertIsNotNone(ca.key(pwd))
def test_path_length(self) -> None:
"""Test the path_length attribute."""
for name, ca in self.cas.items():
- self.assertEqual(ca.path_length, certs[name].get("path_length"))
+ self.assertEqual(ca.path_length, CERT_DATA[name].get("path_length"))
def test_root(self) -> None:
"""Test the root attribute."""
self.assertEqual(self.cas["root"].root, self.cas["root"])
self.assertEqual(self.cas["child"].root, self.cas["root"])
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
@override_tmpcadir()
def test_full_crl(self) -> None:
"""Test getting the CRL for a CertificateAuthority."""
@@ -268,7 +271,7 @@ def test_full_crl(self) -> None:
crl = ca.get_crl().public_bytes(Encoding.PEM)
self.assertCRL(crl, expected=[child], crl_number=4, signer=ca, algorithm=ca.algorithm)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
@override_tmpcadir()
def test_intermediate_crl(self) -> None:
"""Test getting the CRL of an intermediate CA."""
@@ -300,7 +303,7 @@ def test_full_crl_without_timezone_support(self) -> None:
self.test_full_crl()
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_ca_crl(self) -> None:
"""Test getting a CA CRL."""
ca = self.cas["root"]
@@ -319,7 +322,7 @@ def test_ca_crl(self) -> None:
self.assertCRL(crl, expected=[child_ca], idp=idp, crl_number=1, signer=ca, algorithm=ca.algorithm)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_intermediate_ca_crl(self) -> None:
"""Test getting the CRL for an intermediate CA."""
# Intermediate CAs have a DP in the CRL that has the CA url
@@ -329,7 +332,7 @@ def test_intermediate_ca_crl(self) -> None:
crl = self.ca.get_crl(scope="ca").public_bytes(Encoding.PEM)
self.assertCRL(crl, idp=idp, signer=self.ca, algorithm=self.ca.algorithm)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
@override_tmpcadir()
def test_user_crl(self) -> None:
"""Test getting a user CRL."""
@@ -347,7 +350,7 @@ def test_user_crl(self) -> None:
crl = ca.get_crl(scope="user").public_bytes(Encoding.PEM)
self.assertCRL(crl, expected=[cert], idp=idp, crl_number=1, signer=ca, algorithm=ca.algorithm)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
@override_tmpcadir()
def test_attr_crl(self) -> None:
"""Test getting an Attribute CRL (always an empty list)."""
@@ -365,7 +368,7 @@ def test_attr_crl(self) -> None:
self.assertCRL(crl, idp=idp, crl_number=1, signer=ca, algorithm=ca.algorithm)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_no_idp(self) -> None:
"""Test a CRL with no IDP."""
# CRLs require a full name (or only_some_reasons) if it's a full CRL
@@ -375,7 +378,7 @@ def test_no_idp(self) -> None:
self.assertCRL(crl, idp=None, algorithm=self.ca.algorithm)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_counter(self) -> None:
"""Test the counter for CRLs."""
idp = self.get_idp(full_name=self.get_idp_full_name(self.ca))
@@ -388,7 +391,7 @@ def test_counter(self) -> None:
self.assertCRL(crl, idp=idp, crl_number=0, algorithm=self.ca.algorithm)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_no_auth_key_identifier(self) -> None:
"""Test getting the CRL from a CA with no AuthorityKeyIdentifier."""
@@ -406,7 +409,7 @@ def side_effect(cls: Any) -> typing.NoReturn:
# Note that we still get an AKI because the value comes from the public key in this case
self.assertCRL(crl, idp=idp, signer=self.ca, algorithm=self.ca.algorithm)
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_get_crl_with_wrong_algorithm(self) -> None:
"""Test that we validate the algorithm if passed by the user."""
# DSA/RSA/EC keys cannot trigger this condition, as the algorithm would default to the one used by
@@ -434,7 +437,7 @@ def test_crl_invalid_scope(self) -> None:
self.ca.get_crl(scope="foobar").public_bytes(Encoding.PEM) # type: ignore[arg-type]
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_cache_crls(self) -> None:
"""Test caching of CRLs."""
crl_profiles = self.crl_profiles
@@ -590,7 +593,7 @@ def test_cache_crls_algorithm(self) -> None:
def test_max_path_length(self) -> None:
"""Test getting the maximum path_length."""
for name, ca in self.usable_cas:
- self.assertEqual(ca.max_path_length, certs[name].get("max_path_length"), name)
+ self.assertEqual(ca.max_path_length, CERT_DATA[name].get("max_path_length"), name)
def test_allows_intermediate(self) -> None:
"""Test checking if this CA allows intermediate CAs."""
@@ -638,7 +641,7 @@ def test_generate_ocsp_responder_certificate_for_rsa_ca_with_custom_curve(self)
@override_tmpcadir()
def test_regenerate_ocsp_responder_certificate(self) -> None:
"""Test regenerating an OCSP responder certificate that is due to expire soon."""
- with freeze_time(timestamps["everything_valid"]) as frozen_time:
+ with freeze_time(TIMESTAMPS["everything_valid"]) as frozen_time:
# TYPEHINT NOTE: We know that the certificate was not yet generated here
_, _, ocsp_responder_certificate = self.ca.generate_ocsp_key() # type: ignore[misc]
@@ -763,7 +766,7 @@ class CertificateAuthoritySignTests(TestCaseMixin, X509CertMixinTestCaseMixin, T
"""Test signing a certificiate."""
load_cas = ("root", "child")
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
def assertBasicCert(self, cert: x509.Certificate) -> None: # pylint: disable=invalid-name
"""Basic assertions about the certificate."""
@@ -782,12 +785,12 @@ def assertExtensionDict( # pylint: disable=invalid-name
self.assertEqual(actual, expected_dict)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_simple(self) -> None:
"""Test the simplest invocation of the function."""
now = datetime.now(tz=tz.utc).replace(tzinfo=None)
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
with self.assertSignCertSignals():
cert = self.ca.sign(csr, subject=subject)
@@ -807,11 +810,11 @@ def test_simple(self) -> None:
)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_non_default_values(self) -> None:
"""Pass non-default parameters."""
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
algorithm = hashes.SHA256()
expires = datetime.now(tz=tz.utc) + ca_settings.CA_DEFAULT_EXPIRES + timedelta(days=3)
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
@@ -823,11 +826,11 @@ def test_non_default_values(self) -> None:
self.assertIsInstance(cert.signature_hash_algorithm, hashes.SHA256)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_non_default_extensions(self) -> None:
"""Pass non-default extensions."""
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
aki = x509.Extension(
oid=ExtensionOID.AUTHORITY_KEY_IDENTIFIER,
@@ -854,11 +857,11 @@ def test_non_default_extensions(self) -> None:
self.assertExtensionDict(cert, [ski, basic_constraints(critical=False), aki])
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_cn_not_in_san(self) -> None:
"""Test the cn_in_san option."""
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
san = subject_alternative_name(dns("example.net"))
with self.assertSignCertSignals():
@@ -876,11 +879,11 @@ def test_cn_not_in_san(self) -> None:
)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_append_cn_to_san(self) -> None:
"""Test appending a CommonName to SubjectAlternativeName."""
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
san = subject_alternative_name(dns("example.net"))
with self.assertSignCertSignals():
@@ -898,11 +901,11 @@ def test_append_cn_to_san(self) -> None:
)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_cn_already_in_san(self) -> None:
"""Test using a CommonName that is already in SubjectAlternativeName."""
cn = "example.com"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
san = subject_alternative_name(dns(cn))
with self.assertSignCertSignals():
@@ -920,11 +923,11 @@ def test_cn_already_in_san(self) -> None:
)
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_unparsable_cn(self) -> None:
"""Test using a CommonName that cannot be used as a SubjectAlternativeName."""
cn = "foo..bar*"
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
san = subject_alternative_name(dns("example.net"))
with self.assertSignCertSignals():
@@ -943,7 +946,7 @@ def test_unparsable_cn(self) -> None:
def test_create_ca(self) -> None:
"""Try passing a BasicConstraints extension that allows creating a CA."""
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "example.com")])
msg = r"^This function cannot be used to create a Certificate Authority\.$"
with self.assertSignCertSignals(pre=False, post=False), self.assertRaisesRegex(ValueError, msg):
@@ -970,25 +973,25 @@ def test_bundle_as_pem(self) -> None:
def test_dates(self) -> None:
"""Test valid_from/valid_until dates."""
for name, ca in self.cas.items():
- self.assertEqual(ca.valid_from, timezone.make_aware(certs[name]["valid_from"], tz.utc))
- self.assertEqual(ca.expires, timezone.make_aware(certs[name]["valid_until"], tz.utc))
+ self.assertEqual(ca.valid_from, timezone.make_aware(CERT_DATA[name]["valid_from"], tz.utc))
+ self.assertEqual(ca.expires, timezone.make_aware(CERT_DATA[name]["valid_until"], tz.utc))
for name, cert in self.certs.items():
- self.assertEqual(cert.valid_from, timezone.make_aware(certs[name]["valid_from"], tz.utc))
- self.assertEqual(cert.expires, timezone.make_aware(certs[name]["valid_until"], tz.utc))
+ self.assertEqual(cert.valid_from, timezone.make_aware(CERT_DATA[name]["valid_from"], tz.utc))
+ self.assertEqual(cert.expires, timezone.make_aware(CERT_DATA[name]["valid_until"], tz.utc))
@override_settings(USE_TZ=False)
def test_dates_without_timezone_support(self) -> None:
"""Test valid_from/valid_until dates without timezone support."""
for name, ca in self.cas.items():
ca.refresh_from_db() # obj is loaded in setUp(), before decorator is active
- self.assertEqual(ca.valid_from, certs[name]["valid_from"])
- self.assertEqual(ca.expires, certs[name]["valid_until"])
+ self.assertEqual(ca.valid_from, CERT_DATA[name]["valid_from"])
+ self.assertEqual(ca.expires, CERT_DATA[name]["valid_until"])
for name, cert in self.certs.items():
cert.refresh_from_db() # obj is loaded in setUp(), before decorator is active
- self.assertEqual(cert.valid_from, certs[name]["valid_from"])
- self.assertEqual(cert.expires, certs[name]["valid_until"])
+ self.assertEqual(cert.valid_from, CERT_DATA[name]["valid_from"])
+ self.assertEqual(cert.expires, CERT_DATA[name]["valid_until"])
def test_revocation(self) -> None:
"""Test getting a revociation for a non-revoked certificate."""
@@ -1007,10 +1010,10 @@ def test_root(self) -> None:
def test_serial(self) -> None:
"""Test getting the serial."""
for name, ca in self.cas.items():
- self.assertEqual(ca.serial, certs[ca.name].get("serial"))
+ self.assertEqual(ca.serial, CERT_DATA[ca.name].get("serial"))
for name, cert in self.certs.items():
- self.assertEqual(cert.serial, certs[name].get("serial"))
+ self.assertEqual(cert.serial, CERT_DATA[name].get("serial"))
@override_tmpcadir()
def test_subject_alternative_name(self) -> None:
@@ -1018,13 +1021,13 @@ def test_subject_alternative_name(self) -> None:
for name, ca in self.cas.items():
self.assertEqual(
ca.x509_extensions.get(ExtensionOID.SUBJECT_ALTERNATIVE_NAME),
- certs[ca.name].get("subject_alternative_name"),
+ CERT_DATA[ca.name].get("subject_alternative_name"),
)
for name, cert in self.certs.items():
self.assertEqual(
cert.x509_extensions.get(ExtensionOID.SUBJECT_ALTERNATIVE_NAME),
- certs[name].get("subject_alternative_name"),
+ CERT_DATA[name].get("subject_alternative_name"),
)
# Create a cert with some weirder SANs to test that too
@@ -1035,7 +1038,7 @@ def test_subject_alternative_name(self) -> None:
)
weird_cert = self.create_cert(
self.cas["child"],
- certs["child-cert"]["csr"]["parsed"],
+ CERT_DATA["child-cert"]["csr"]["parsed"],
subject=self.subject,
extensions=[san],
)
@@ -1121,21 +1124,21 @@ def test_get_fingerprint(self) -> None:
}
for name, ca in self.cas.items():
for algo_name, algorithm in algorithms.items():
- self.assertEqual(ca.get_fingerprint(algorithm), certs[name][algo_name])
+ self.assertEqual(ca.get_fingerprint(algorithm), CERT_DATA[name][algo_name])
for name, cert in self.certs.items():
for algo_name, algorithm in algorithms.items():
- self.assertEqual(cert.get_fingerprint(algorithm), certs[name][algo_name])
+ self.assertEqual(cert.get_fingerprint(algorithm), CERT_DATA[name][algo_name])
def test_jwk(self) -> None:
"""Test JWK property."""
for name, ca in self.cas.items():
# josepy does not support loading DSA/Ed448/Ed25519 keys:
# https://github.com/certbot/josepy/pull/98
- if certs[name]["key_type"] in ("DSA", "Ed448", "Ed25519"):
+ if CERT_DATA[name]["key_type"] in ("DSA", "Ed448", "Ed25519"):
continue
- if certs[name]["key_type"] == "EC":
+ if CERT_DATA[name]["key_type"] == "EC":
self.assertIsInstance(ca.jwk, jose.jwk.JWKEC, name)
else:
self.assertIsInstance(ca.jwk, jose.jwk.JWKRSA, name)
@@ -1143,10 +1146,10 @@ def test_jwk(self) -> None:
for name, cert in self.certs.items():
# josepy does not support loading DSA/Ed448/Ed25519 keys:
# https://github.com/certbot/josepy/pull/98
- if certs[name]["key_type"] in ("DSA", "Ed448", "Ed25519"):
+ if CERT_DATA[name]["key_type"] in ("DSA", "Ed448", "Ed25519"):
continue
- if certs[name]["key_type"] == "EC":
+ if CERT_DATA[name]["key_type"] == "EC":
self.assertIsInstance(cert.jwk, jose.jwk.JWKEC, name)
else:
self.assertIsInstance(cert.jwk, jose.jwk.JWKRSA, name)
@@ -1201,7 +1204,7 @@ def test_get_authority_key_identifier(self) -> None:
for name, ca in self.cas.items():
self.assertEqual(
ca.get_authority_key_identifier().key_identifier,
- certs[name]["subject_key_identifier"].value.key_identifier,
+ CERT_DATA[name]["subject_key_identifier"].value.key_identifier,
)
# All CAs have a subject key identifier, so we mock that this exception is not present
@@ -1214,7 +1217,7 @@ def side_effect(cls: Any) -> typing.NoReturn:
):
self.assertEqual(
ca.get_authority_key_identifier().key_identifier,
- certs["child"]["subject_key_identifier"].value.key_identifier,
+ CERT_DATA["child"]["subject_key_identifier"].value.key_identifier,
)
def test_get_authority_key_identifier_extension(self) -> None:
@@ -1222,7 +1225,7 @@ def test_get_authority_key_identifier_extension(self) -> None:
for name, ca in self.cas.items():
ext = ca.get_authority_key_identifier_extension()
self.assertEqual(
- ext.value.key_identifier, certs[name]["subject_key_identifier"].value.key_identifier
+ ext.value.key_identifier, CERT_DATA[name]["subject_key_identifier"].value.key_identifier
)
def test_inconsistent_model_states(self) -> None:
@@ -1244,8 +1247,8 @@ def test_inconsistent_model_states(self) -> None:
class ModelfieldsTests(TestCaseMixin, TestCase):
"""Specialized tests for model fields."""
- csr = certs["root-cert"]["csr"]
- pub = certs["root-cert"]["pub"]
+ csr = CERT_DATA["root-cert"]["csr"]
+ pub = CERT_DATA["root-cert"]["pub"]
load_cas = ("root",)
def test_create_pem_bytes(self) -> None:
@@ -1417,7 +1420,7 @@ def test_invalid_value(self) -> None:
"""Test passing invalid values."""
with self.assertRaisesRegex(ValueError, r"^True: Could not parse CertificateSigningRequest$"):
Certificate.objects.create(
- pub=certs["child-cert"]["pub"]["parsed"],
+ pub=CERT_DATA["child-cert"]["pub"]["parsed"],
csr=True,
ca=self.ca,
expires=timezone.now(),
@@ -1426,7 +1429,7 @@ def test_invalid_value(self) -> None:
with self.assertRaisesRegex(ValueError, r"^True: Could not parse Certificate$"):
Certificate.objects.create(
- csr=certs["child-cert"]["csr"]["parsed"],
+ csr=CERT_DATA["child-cert"]["csr"]["parsed"],
pub=True,
ca=self.ca,
expires=timezone.now(),
@@ -1480,7 +1483,7 @@ def test_serial(self) -> None:
with self.assertRaisesRegex(AcmeAccount.ca.RelatedObjectDoesNotExist, r"^AcmeAccount has no ca\.$"):
AcmeAccount().serial # pylint: disable=expression-not-assigned
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_usable(self) -> None:
"""Test the ``usable`` property."""
self.assertTrue(self.account1.usable)
@@ -1731,7 +1734,7 @@ def test_acme_challenge(self) -> None:
with self.assertRaisesRegex(ValueError, r"^foo: Unsupported challenge type\.$"):
self.chall.acme_challenge # pylint: disable=pointless-statement
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_acme_validated(self) -> None:
"""Test acme_validated property."""
# preconditions for checks (might change them in setUp without realising it might affect this test)
@@ -1744,12 +1747,12 @@ def test_acme_validated(self) -> None:
self.assertIsNone(self.chall.acme_validated) # still None (no validated timestamp)
self.chall.validated = timezone.now()
- self.assertEqual(self.chall.acme_validated, timestamps["everything_valid"])
+ self.assertEqual(self.chall.acme_validated, TIMESTAMPS["everything_valid"])
# We return a UTC timestamp, even if timezone support is disabled.
with self.settings(USE_TZ=False):
self.chall.validated = timezone.now()
- self.assertEqual(self.chall.acme_validated, timestamps["everything_valid"])
+ self.assertEqual(self.chall.acme_validated, TIMESTAMPS["everything_valid"])
def test_encoded(self) -> None:
"""Test the encoded property."""
@@ -1817,5 +1820,5 @@ def test_acme_url(self) -> None:
def test_parse_csr(self) -> None:
"""Test the parse_csr property."""
- self.acme_cert.csr = certs["root-cert"]["csr"]["pem"]
+ self.acme_cert.csr = CERT_DATA["root-cert"]["csr"]["pem"]
self.assertIsInstance(self.acme_cert.parse_csr(), x509.CertificateSigningRequest)
diff --git a/ca/django_ca/tests/test_profiles.py b/ca/django_ca/tests/test_profiles.py
index fe771e944..7740b7463 100644
--- a/ca/django_ca/tests/test_profiles.py
+++ b/ca/django_ca/tests/test_profiles.py
@@ -28,15 +28,18 @@
from django_ca.models import Certificate, CertificateAuthority
from django_ca.profiles import Profile, get_profile, profile, profiles
from django_ca.signals import pre_sign_cert
-from django_ca.tests.base import certs, dns, override_tmpcadir, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.utils import (
authority_information_access,
basic_constraints,
+ dns,
issuer_alternative_name,
ocsp_no_check,
+ override_tmpcadir,
subject_alternative_name,
subject_key_identifier,
+ uri,
)
@@ -45,7 +48,7 @@ class DocumentationTestCase(TestCaseMixin, TestCase):
def setUp(self) -> None:
super().setUp()
- self.ca = self.load_ca(name=certs["root"]["name"], parsed=certs["root"]["pub"]["parsed"])
+ self.ca = self.load_ca(name=CERT_DATA["root"]["name"], parsed=CERT_DATA["root"]["pub"]["parsed"])
def get_globs(self) -> Dict[str, Any]:
"""Get globals for doctests."""
@@ -54,7 +57,7 @@ def get_globs(self) -> Dict[str, Any]:
"get_profile": get_profile,
"ca": self.ca,
"ca_serial": self.ca.serial,
- "csr": certs["root-cert"]["csr"]["parsed"],
+ "csr": CERT_DATA["root-cert"]["csr"]["parsed"],
}
@override_tmpcadir()
@@ -185,8 +188,8 @@ def test_serialize(self) -> None:
@override_tmpcadir()
def test_create_cert_minimal(self) -> None:
"""Create a certificate with minimal parameters."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[])
with self.mockSignal(pre_sign_cert) as pre:
@@ -207,10 +210,10 @@ def test_create_cert_minimal(self) -> None:
@override_tmpcadir()
def test_alternative_values(self) -> None:
"""Test overriding most values."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
ca.issuer_alt_name = "https://example.com"
ca.save()
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
country_name = x509.NameAttribute(NameOID.COUNTRY_NAME, "AT")
subject = x509.Name([country_name, x509.NameAttribute(NameOID.COMMON_NAME, self.hostname)])
@@ -241,8 +244,8 @@ def test_alternative_values(self) -> None:
@override_tmpcadir()
def test_overrides(self) -> None:
"""Test other overrides."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
country_name = x509.NameAttribute(NameOID.COUNTRY_NAME, "AT")
expected_subject = x509.Name([country_name, x509.NameAttribute(NameOID.COMMON_NAME, self.hostname)])
@@ -297,8 +300,8 @@ def test_overrides(self) -> None:
@override_tmpcadir()
def test_none_extension(self) -> None:
"""Test passing an extension that is removed by the profile."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[("C", "AT")], extensions={"ocsp_no_check": None})
with self.mockSignal(pre_sign_cert) as pre:
@@ -309,8 +312,8 @@ def test_none_extension(self) -> None:
@override_tmpcadir()
def test_cn_in_san(self) -> None:
"""Test writing the common name into the SAN."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
subject = x509.Name(
[
x509.NameAttribute(NameOID.COUNTRY_NAME, "AT"),
@@ -387,8 +390,8 @@ def test_cn_in_san(self) -> None:
@override_tmpcadir()
def test_override_ski(self) -> None:
"""Test overriding the subject key identifier."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
ski = x509.Extension(
oid=ExtensionOID.SUBJECT_KEY_IDENTIFIER,
critical=False,
@@ -425,8 +428,8 @@ def test_override_ski(self) -> None:
def test_add_distribution_point_with_ca_crldp(self) -> None:
"""Pass a custom distribution point when creating the cert, which matches ca.crl_url."""
prof = Profile("example", subject=[])
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
# Add CRL url to CA
ca.crl_url = "https://crl.ca.example.com"
@@ -465,8 +468,8 @@ def test_add_distribution_point_with_ca_crldp(self) -> None:
@override_tmpcadir()
def test_with_algorithm(self) -> None:
"""Test a profile that manually overrides the algorithm."""
- root = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ root = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[], algorithm="SHA-512")
@@ -491,8 +494,8 @@ def test_with_algorithm(self) -> None:
def test_issuer_alternative_name_override(self) -> None:
"""Pass a custom Issuer Alternative Name which overwrites the CA value."""
prof = Profile("example", subject=[])
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
# Add CRL url to CA
ca.issuer_alt_name = "https://ian.ca.example.com"
@@ -532,8 +535,8 @@ def test_issuer_alternative_name_override(self) -> None:
def test_merge_authority_information_access_existing_values(self) -> None:
"""Pass a custom distribution point when creating the cert, which matches ca.crl_url."""
prof = Profile("example", subject=[])
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
# Add CRL url to CA
ca.ocsp_url = "https://ocsp.ca.example.com"
@@ -581,8 +584,8 @@ def test_merge_authority_information_access_existing_values(self) -> None:
@override_tmpcadir()
def test_extension_as_cryptography(self) -> None:
"""Test with a profile that has cryptography extensions."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[], extensions={EXTENSION_KEYS[ExtensionOID.OCSP_NO_CHECK]: {}})
with self.mockSignal(pre_sign_cert) as pre:
@@ -620,13 +623,13 @@ def test_extension_overrides(self) -> None:
)
},
)
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
ca.ocsp_url = "http://ocsp.example.com/ca"
ca.issuer_url = "http://issuer.example.com/issuer"
ca.save()
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
expected_authority_information_access = authority_information_access(
ocsp=[uri("http://ocsp.example.com/expected")],
@@ -665,13 +668,13 @@ def test_partial_authority_information_access_override(self) -> None:
)
},
)
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
ca.ocsp_url = "http://ocsp.example.com/ca"
ca.issuer_url = "http://issuer.example.com/ca"
ca.save()
- csr = certs["child-cert"]["csr"]["parsed"]
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
# Only pass an OCSP responder
with self.mockSignal(pre_sign_cert) as pre:
@@ -732,8 +735,8 @@ def test_partial_authority_information_access_override(self) -> None:
@override_tmpcadir()
def test_no_cn_no_san(self) -> None:
"""Test creating a cert with no cn in san."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[("C", "AT")])
msg = r"^Must name at least a CN or a subjectAlternativeName\.$"
@@ -744,8 +747,8 @@ def test_no_cn_no_san(self) -> None:
@override_tmpcadir()
def test_no_valid_cn_in_san(self) -> None:
"""Test what happens when the SAN has nothing usable as CN."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("example", subject=[], extensions={EXTENSION_KEYS[ExtensionOID.OCSP_NO_CHECK]: {}})
san = subject_alternative_name(x509.RegisteredID(ExtensionOID.OCSP_NO_CHECK))
@@ -756,8 +759,8 @@ def test_no_valid_cn_in_san(self) -> None:
@override_tmpcadir()
def test_unparsable_cn(self) -> None:
"""Try creating a profile with an unparsable Common Name."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
cname = "foo bar"
prof = Profile("example", subject=[("C", "AT"), ("CN", cname)])
@@ -774,8 +777,8 @@ def test_unknown_signature_hash_algorithm(self) -> None:
@override_tmpcadir(CA_DEFAULT_SUBJECT=None)
def test_no_valid_subject(self) -> None:
"""Test case where no subject at all could be determined."""
- ca = self.load_ca(name="root", parsed=certs["root"]["pub"]["parsed"])
- csr = certs["child-cert"]["csr"]["parsed"]
+ ca = self.load_ca(name="root", parsed=CERT_DATA["root"]["pub"]["parsed"])
+ csr = CERT_DATA["child-cert"]["csr"]["parsed"]
prof = Profile("test")
with self.assertRaisesRegex(ValueError, r"^Cannot determine subject for certificate\.$"):
self.create_cert(prof, ca, csr)
diff --git a/ca/django_ca/tests/test_querysets.py b/ca/django_ca/tests/test_querysets.py
index af292d9b9..99955e870 100644
--- a/ca/django_ca/tests/test_querysets.py
+++ b/ca/django_ca/tests/test_querysets.py
@@ -38,9 +38,9 @@
Certificate,
CertificateAuthority,
)
-from django_ca.tests.base import override_tmpcadir, timestamps
+from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import AcmeValuesMixin, TestCaseMixin
-from django_ca.tests.base.utils import basic_constraints, key_usage
+from django_ca.tests.base.utils import basic_constraints, key_usage, override_tmpcadir
from django_ca.utils import x509_name
@@ -258,23 +258,23 @@ def test_valid(self) -> None:
"""Test valid/usable/invalid filters."""
self.load_named_cas("__usable__")
- with freeze_time(timestamps["before_cas"]):
+ with freeze_time(TIMESTAMPS["before_cas"]):
self.assertCountEqual(CertificateAuthority.objects.valid(), [])
self.assertCountEqual(CertificateAuthority.objects.usable(), [])
self.assertCountEqual(CertificateAuthority.objects.invalid(), self.cas.values())
- with freeze_time(timestamps["before_child"]):
+ with freeze_time(TIMESTAMPS["before_child"]):
valid = [c for c in self.cas.values() if c.name != "child"]
self.assertCountEqual(CertificateAuthority.objects.valid(), valid)
self.assertCountEqual(CertificateAuthority.objects.usable(), valid)
self.assertCountEqual(CertificateAuthority.objects.invalid(), [self.cas["child"]])
- with freeze_time(timestamps["after_child"]):
+ with freeze_time(TIMESTAMPS["after_child"]):
self.assertCountEqual(CertificateAuthority.objects.valid(), self.cas.values())
self.assertCountEqual(CertificateAuthority.objects.usable(), self.cas.values())
self.assertCountEqual(CertificateAuthority.objects.invalid(), [])
- with freeze_time(timestamps["cas_expired"]):
+ with freeze_time(TIMESTAMPS["cas_expired"]):
self.assertCountEqual(CertificateAuthority.objects.valid(), [])
self.assertCountEqual(CertificateAuthority.objects.usable(), [])
self.assertCountEqual(CertificateAuthority.objects.invalid(), self.cas.values())
@@ -288,17 +288,17 @@ class CertificateQuerysetTestCase(QuerySetTestCaseMixin, TestCase):
def test_validity(self) -> None:
"""Test validity filter."""
- with freeze_time(timestamps["everything_valid"]):
+ with freeze_time(TIMESTAMPS["everything_valid"]):
self.assertQuerySet(Certificate.objects.expired())
self.assertQuerySet(Certificate.objects.not_yet_valid())
self.assertQuerySet(Certificate.objects.valid(), *self.certs.values())
- with freeze_time(timestamps["everything_expired"]):
+ with freeze_time(TIMESTAMPS["everything_expired"]):
self.assertQuerySet(Certificate.objects.expired(), *self.certs.values())
self.assertQuerySet(Certificate.objects.not_yet_valid())
self.assertQuerySet(Certificate.objects.valid())
- with freeze_time(timestamps["before_everything"]):
+ with freeze_time(TIMESTAMPS["before_everything"]):
self.assertQuerySet(Certificate.objects.expired())
self.assertQuerySet(Certificate.objects.not_yet_valid(), *self.certs.values())
self.assertQuerySet(Certificate.objects.valid())
@@ -313,7 +313,7 @@ def test_validity(self) -> None:
self.certs["ed25519-cert"],
]
valid = [c for c in self.certs.values() if c not in expired]
- with freeze_time(timestamps["ca_certs_expired"]):
+ with freeze_time(TIMESTAMPS["ca_certs_expired"]):
self.assertQuerySet(Certificate.objects.expired(), *expired)
self.assertQuerySet(Certificate.objects.not_yet_valid())
self.assertQuerySet(Certificate.objects.valid(), *valid)
@@ -362,7 +362,7 @@ def setUp(self) -> None:
class AcmeAccountQuerySetTestCase(AcmeQuerySetTestCase):
"""Test cases for :py:class:`~django_ca.querysets.AcmeAccountQuerySet`."""
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_viewable(self) -> None:
"""Test the viewable() method."""
self.assertQuerySet(AcmeAccount.objects.viewable(), self.account, self.account2)
@@ -379,7 +379,7 @@ def test_viewable(self) -> None:
# Test that we're back to the original state
self.assertQuerySet(AcmeAccount.objects.viewable(), self.account, self.account2)
- with freeze_time(timestamps["everything_expired"]):
+ with freeze_time(TIMESTAMPS["everything_expired"]):
self.assertQuerySet(AcmeAccount.objects.viewable())
@@ -391,7 +391,7 @@ def test_account(self) -> None:
self.assertQuerySet(AcmeOrder.objects.account(self.account), self.order)
self.assertQuerySet(AcmeOrder.objects.account(self.account2))
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_viewable(self) -> None:
"""Test the viewable() method."""
self.assertQuerySet(AcmeOrder.objects.viewable(), self.order)
@@ -399,7 +399,7 @@ def test_viewable(self) -> None:
with self.attr(self.order.account, "status", AcmeAccount.STATUS_REVOKED):
self.assertQuerySet(AcmeOrder.objects.viewable())
- with freeze_time(timestamps["everything_expired"]):
+ with freeze_time(TIMESTAMPS["everything_expired"]):
self.assertQuerySet(AcmeOrder.objects.viewable())
@@ -411,7 +411,7 @@ def test_account(self) -> None:
self.assertQuerySet(AcmeAuthorization.objects.account(self.account), self.auth)
self.assertQuerySet(AcmeAuthorization.objects.account(self.account2))
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_url(self) -> None:
"""Test the url filter."""
# pylint: disable=expression-not-assigned
@@ -419,7 +419,7 @@ def test_url(self) -> None:
with self.assertNumQueries(1):
AcmeAuthorization.objects.url().get(pk=self.auth.pk).acme_url
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_viewable(self) -> None:
"""Test the viewable() method."""
self.assertQuerySet(AcmeAuthorization.objects.viewable(), self.auth)
@@ -436,7 +436,7 @@ def test_account(self) -> None:
self.assertQuerySet(AcmeChallenge.objects.account(self.account), self.chall)
self.assertQuerySet(AcmeChallenge.objects.account(self.account2))
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_url(self) -> None:
"""Test the url filter."""
# pylint: disable=expression-not-assigned
@@ -444,7 +444,7 @@ def test_url(self) -> None:
with self.assertNumQueries(1):
AcmeChallenge.objects.url().get(pk=self.chall.pk).acme_url
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_viewable(self) -> None:
"""Test the viewable() method."""
self.assertQuerySet(AcmeChallenge.objects.viewable(), self.chall)
@@ -461,7 +461,7 @@ def test_account(self) -> None:
self.assertQuerySet(AcmeCertificate.objects.account(self.account), self.acme_cert)
self.assertQuerySet(AcmeCertificate.objects.account(self.account2))
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_url(self) -> None:
"""Test the url filter."""
# pylint: disable=expression-not-assigned
@@ -469,7 +469,7 @@ def test_url(self) -> None:
with self.assertNumQueries(1):
AcmeCertificate.objects.url().get(pk=self.acme_cert.pk).acme_url
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_viewable(self) -> None:
"""Test the viewable() method."""
# none by default because we need a valid order and cert
diff --git a/ca/django_ca/tests/test_settings.py b/ca/django_ca/tests/test_settings.py
index 80bcf5d8c..eed935e3b 100644
--- a/ca/django_ca/tests/test_settings.py
+++ b/ca/django_ca/tests/test_settings.py
@@ -35,7 +35,7 @@
update_database_setting_from_environment,
)
from django_ca import ca_settings
-from django_ca.tests.base import FIXTURES_DIR
+from django_ca.tests.base.constants import FIXTURES_DIR
from django_ca.tests.base.mixins import TestCaseMixin
@@ -522,7 +522,7 @@ def test_invalid_key(self) -> None:
with self.settings(CA_DEFAULT_SUBJECT=[("invalid", "wrong")]):
pass
- def test_invalid_ocsp_repsonder_certificate_renewal(self) -> None:
+ def test_invalid_ocsp_responder_certificate_renewal(self) -> None:
"""Test the CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL setting."""
with self.assertImproperlyConfigured(
r"^CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL must be a timedelta or int\.$"
diff --git a/ca/django_ca/tests/test_tasks.py b/ca/django_ca/tests/test_tasks.py
index 14ff916f6..bdbe8df04 100644
--- a/ca/django_ca/tests/test_tasks.py
+++ b/ca/django_ca/tests/test_tasks.py
@@ -49,9 +49,9 @@
AcmeOrder,
Certificate,
)
-from django_ca.tests.base import certs, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.mixins import AcmeValuesMixin, TestCaseMixin
-from django_ca.tests.base.utils import subject_alternative_name
+from django_ca.tests.base.utils import override_tmpcadir, subject_alternative_name
from django_ca.utils import ca_storage, get_crl_cache_key
@@ -112,7 +112,7 @@ def test_basic(self) -> None:
self.assertIsInstance(crl.signature_hash_algorithm, type(ca.algorithm))
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_cache_all_crls(self) -> None:
"""Test caching when all CAs are valid."""
enc_cls = Encoding.DER
@@ -131,7 +131,7 @@ def test_cache_all_crls(self) -> None:
crl = x509.load_der_x509_crl(cache.get(key))
@override_tmpcadir()
- @freeze_time(timestamps["everything_expired"])
+ @freeze_time(TIMESTAMPS["everything_expired"])
def test_cache_all_crls_expired(self) -> None:
"""Test that nothing is cashed if all CAs are expired."""
tasks.cache_crls()
@@ -153,7 +153,7 @@ def test_no_private_key(self) -> None:
tasks.cache_crl(self.cas["pwd"].serial)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class GenerateOCSPKeysTestCase(TestCaseMixin, TestCase):
"""Test the generate_ocsp_key task."""
@@ -177,7 +177,7 @@ def test_all(self) -> None:
self.assertTrue(ca_storage.exists(f"ocsp/{ca.serial}.pem"))
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_repsonder_key_validity(self) -> None:
"""Test that the ocsp_responder_key_validity field works."""
ca = self.cas["root"]
@@ -188,10 +188,10 @@ def test_repsonder_key_validity(self) -> None:
tasks.generate_ocsp_key(ca.serial)
cert = qs.get()
- self.assertEqual(cert.expires, timestamps["everything_valid"] + timedelta(days=10))
+ self.assertEqual(cert.expires, TIMESTAMPS["everything_valid"] + timedelta(days=10))
@override_tmpcadir()
- @freeze_time(timestamps["everything_valid"])
+ @freeze_time(TIMESTAMPS["everything_valid"])
def test_no_renewal_required(self) -> None:
"""Test that keys are not renewed and None is returned in this case."""
self.assertIsNotNone(tasks.generate_ocsp_key(self.ca.serial))
@@ -350,7 +350,7 @@ def test_multiple_auths(self) -> None:
self.assertValid(AcmeOrder.STATUS_PENDING)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeValidateHttp01ChallengeTestCase(AcmeValidateChallengeTestCaseMixin, TestCase):
"""Test :py:func:`~django_ca.tasks.acme_validate_challenge`."""
@@ -408,7 +408,7 @@ def test_request_exception(self) -> None:
self.assertEqual(logcm.output[1], f"INFO:django_ca.tasks:{str(self.chall)} is invalid")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeValidateDns01ChallengeTestCase(AcmeValidateChallengeTestCaseMixin, TestCase):
"""Test :py:func:`~django_ca.tasks.acme_validate_challenge`."""
@@ -475,7 +475,7 @@ def test_nxdomain(self) -> None:
)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeIssueCertificateTestCase(TestCaseMixin, AcmeValuesMixin, TestCase):
"""Test :py:func:`~django_ca.tasks.acme_issue_certificate`."""
@@ -496,7 +496,7 @@ def setUp(self) -> None:
# NOTE: This is of course not the right CSR for the order. It would be validated on submission, and
# all data from the CSR is discarded anyway.
self.acme_cert = AcmeCertificate.objects.create(
- order=self.order, csr=certs["root-cert"]["csr"]["pem"]
+ order=self.order, csr=CERT_DATA["root-cert"]["csr"]["pem"]
)
def test_acme_disabled(self) -> None:
@@ -628,7 +628,7 @@ def test_profile(self) -> None:
self.assertEqual(self.acme_cert.cert.profile, "client")
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCleanupTestCase(TestCaseMixin, AcmeValuesMixin, TestCase):
"""Test :py:func:`~django_ca.tasks.acme_cleanup`."""
@@ -652,7 +652,7 @@ def setUp(self) -> None:
# NOTE: This is of course not the right CSR for the order. It would be validated on submission, and
# all data from the CSR is discarded anyway.
self.acme_cert = AcmeCertificate.objects.create(
- order=self.order, csr=certs["root-cert"]["csr"]["pem"]
+ order=self.order, csr=CERT_DATA["root-cert"]["csr"]["pem"]
)
def test_basic(self) -> None:
diff --git a/ca/django_ca/tests/test_utils.py b/ca/django_ca/tests/test_utils.py
index d3c6a36d9..26d5e522f 100644
--- a/ca/django_ca/tests/test_utils.py
+++ b/ca/django_ca/tests/test_utils.py
@@ -38,7 +38,8 @@
from freezegun import freeze_time
from django_ca import ca_settings, constants, utils
-from django_ca.tests.base import CRYPTOGRAPHY_VERSION, dns, rdn, uri
+from django_ca.tests.base.constants import CRYPTOGRAPHY_VERSION
+from django_ca.tests.base.utils import dns, rdn, uri
from django_ca.utils import (
bytes_to_hex,
format_general_name,
diff --git a/ca/django_ca/tests/test_verification.py b/ca/django_ca/tests/test_verification.py
index a2c41e967..389b49116 100644
--- a/ca/django_ca/tests/test_verification.py
+++ b/ca/django_ca/tests/test_verification.py
@@ -27,8 +27,9 @@
from django.urls import reverse
from django_ca.models import CertificateAuthority, X509CertMixin
-from django_ca.tests.base import certs, override_tmpcadir, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir, uri
class CRLValidationTestCase(TestCaseMixin, TestCase):
@@ -36,7 +37,7 @@ class CRLValidationTestCase(TestCaseMixin, TestCase):
def setUp(self) -> None:
super().setUp()
- self.csr_pem = certs["root-cert"]["csr"]["pem"] # just some CSR
+ self.csr_pem = CERT_DATA["root-cert"]["csr"]["pem"] # just some CSR
def assertFullName( # pylint: disable=invalid-name
self,
diff --git a/ca/django_ca/tests/test_views.py b/ca/django_ca/tests/test_views.py
index 54c29b4bb..602e6f5e3 100644
--- a/ca/django_ca/tests/test_views.py
+++ b/ca/django_ca/tests/test_views.py
@@ -26,8 +26,9 @@
from freezegun import freeze_time
from django_ca import ca_settings
-from django_ca.tests.base import certs, override_tmpcadir, uri
+from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin
+from django_ca.tests.base.utils import override_tmpcadir, uri
from django_ca.views import CertificateRevocationListView
app_name = "django_ca"
@@ -219,7 +220,7 @@ def test_password(self) -> None:
for config in profiles.values():
config.setdefault("OVERRIDES", {})
config["OVERRIDES"].setdefault(ca.serial, {})
- config["OVERRIDES"][ca.serial]["password"] = certs["pwd"]["password"]
+ config["OVERRIDES"][ca.serial]["password"] = CERT_DATA["pwd"]["password"]
with override_settings(CA_CRL_PROFILES=profiles):
ca.cache_crls() # cache CRLs for this CA
diff --git a/ca/django_ca/tests/test_views_ocsp.py b/ca/django_ca/tests/test_views_ocsp.py
index 114b6ef4a..72a8318b2 100644
--- a/ca/django_ca/tests/test_views_ocsp.py
+++ b/ca/django_ca/tests/test_views_ocsp.py
@@ -14,7 +14,6 @@
"""Test OCSP related views."""
import base64
-import os
import typing
from datetime import datetime, timedelta
from http import HTTPStatus
@@ -41,9 +40,10 @@
from django_ca.constants import ReasonFlags
from django_ca.modelfields import LazyCertificate
from django_ca.models import Certificate, CertificateAuthority
-from django_ca.tests.base import FIXTURES_DIR, certs, ocsp_data, override_tmpcadir, timestamps
+from django_ca.tests.base.constants import CERT_DATA, FIXTURES_DATA, FIXTURES_DIR, TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin
from django_ca.tests.base.typehints import HttpResponse
+from django_ca.tests.base.utils import override_tmpcadir
from django_ca.utils import ca_storage, hex_to_bytes
from django_ca.views import OCSPView
@@ -53,18 +53,17 @@
#
# WHERE serial is an int: (int('0x'.replace(':', '').lower(), 0)
def _load_req(req: str) -> bytes:
- cert_path = os.path.join(FIXTURES_DIR, "ocsp", req)
- with open(cert_path, "rb") as stream:
+ with open(FIXTURES_DIR / "ocsp" / req, "rb") as stream:
return stream.read()
-ocsp_profile = certs["profile-ocsp"]
-ocsp_key_path = os.path.join(FIXTURES_DIR, ocsp_profile["key_filename"])
-ocsp_pem_path = os.path.join(FIXTURES_DIR, ocsp_profile["pub_filename"])
+ocsp_profile = CERT_DATA["profile-ocsp"]
+ocsp_key_path = ocsp_profile["key_path"]
+ocsp_pem_path = ocsp_profile["pub_path"]
ocsp_pem = ocsp_profile["pub"]["pem"]
-req1 = _load_req(ocsp_data["nonce"]["filename"])
-req1_nonce = hex_to_bytes(ocsp_data["nonce"]["nonce"])
-req_no_nonce = _load_req(ocsp_data["no-nonce"]["filename"])
+req1 = _load_req(FIXTURES_DATA["ocsp"]["nonce"]["filename"])
+req1_nonce = hex_to_bytes(FIXTURES_DATA["ocsp"]["nonce"]["nonce"])
+req_no_nonce = _load_req(FIXTURES_DATA["ocsp"]["no-nonce"]["filename"])
unknown_req = _load_req("unknown-serial")
multiple_req = _load_req("multiple-serial")
@@ -72,7 +71,7 @@ def _load_req(req: str) -> bytes:
path(
"ocsp/",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert=ocsp_profile["pub_filename"],
expires=1200,
@@ -82,9 +81,9 @@ def _load_req(req: str) -> bytes:
path(
"ocsp/serial/",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
- responder_cert=certs["profile-ocsp"]["serial"],
+ responder_cert=CERT_DATA["profile-ocsp"]["serial"],
expires=1300,
),
name="post-serial",
@@ -92,7 +91,7 @@ def _load_req(req: str) -> bytes:
path(
"ocsp/full-pem/",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert=ocsp_pem,
expires=1400,
@@ -102,9 +101,9 @@ def _load_req(req: str) -> bytes:
path(
"ocsp/loaded-cryptography/",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
- responder_cert=certs["profile-ocsp"]["pub"]["parsed"],
+ responder_cert=CERT_DATA["profile-ocsp"]["pub"]["parsed"],
expires=1500,
),
name="post-loaded-cryptography",
@@ -112,7 +111,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/cert/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert=ocsp_profile["pub_filename"],
),
@@ -121,7 +120,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/ca/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["root"]["serial"],
+ ca=CERT_DATA["root"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert=ocsp_profile["pub_filename"],
ca_ocsp=True,
@@ -140,7 +139,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/false-key/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key="foobar",
responder_cert=ocsp_profile["pub_filename"],
expires=1200,
@@ -151,7 +150,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/false-pem/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert="/false/foobar/",
),
@@ -160,7 +159,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/false-pem-serial/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert="AA:BB:CC",
),
@@ -169,7 +168,7 @@ def _load_req(req: str) -> bytes:
re_path(
r"^ocsp/false-pem-full/(?P[a-zA-Z0-9=+/]+)$",
OCSPView.as_view(
- ca=certs["child"]["serial"],
+ ca=CERT_DATA["child"]["serial"],
responder_key=ocsp_profile["key_filename"],
responder_cert="-----BEGIN CERTIFICATE-----\nvery-mean!",
),
@@ -268,7 +267,7 @@ def assertOCSPResponse( # pylint: disable=invalid-name
self.assertIsInstance(response.responder_key_hash, bytes) # TODO: Validate responder id
# TODO: validate issuer_key_hash, issuer_name_hash
- # Check timestamps
+ # Check TIMESTAMPS
self.assertEqual(response.produced_at, datetime.now())
self.assertEqual(response.this_update, datetime.now())
self.assertEqual(response.next_update, datetime.now() + timedelta(seconds=expires))
@@ -653,18 +652,18 @@ def test_bad_responder_pem(self) -> None:
@override_settings(ROOT_URLCONF=__name__)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class OCSPTestView(OCSPManualViewTestCaseMixin, TestCase):
"""Test manually configured OCSPView."""
@override_settings(ROOT_URLCONF=__name__, USE_TZ=False)
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class OCSPWithoutTimezoneSupportTestView(OCSPManualViewTestCaseMixin, TestCase):
"""Test manually configured OCSPView but with timezone support."""
-@freeze_time(timestamps["everything_valid"])
+@freeze_time(TIMESTAMPS["everything_valid"])
class GenericOCSPViewTestCase(OCSPViewTestMixin, TestCase):
"""Test generic OCSP view."""