Close XCA parity gaps: advanced extensions, CA/revocation UI, imports, ZIP export, E2E
This commit is contained in:
@@ -193,3 +193,116 @@ class RouteExtraTests(unittest.TestCase):
|
||||
assert response.status_code == 204
|
||||
response = await client.get(f"/api/vaults/{vault_id}/certificates/{cert['id']}")
|
||||
assert response.json()["key_id"] is None
|
||||
|
||||
|
||||
class ExtendedRouteTests(unittest.TestCase):
|
||||
@async_test
|
||||
async def test_preview_advanced_extensions(self) -> None:
|
||||
async with api_client() as client:
|
||||
with oidc_user("alice"):
|
||||
vault_id = await _vault(client)
|
||||
key = await _key(client, vault_id)
|
||||
payload = {
|
||||
"name": "preview",
|
||||
"key_id": key["id"],
|
||||
"subject": _subject("preview"),
|
||||
"extensions": {
|
||||
"basic_constraints": {"critical": True, "ca": False, "path_length": None},
|
||||
"crl_distribution_points": {"critical": False, "urls": ["http://example.com/ca.crl"]},
|
||||
"authority_information_access": {
|
||||
"critical": False,
|
||||
"descriptions": [{"method": "ocsp", "location": {"type": "uri", "value": "http://ocsp.example.com"}}],
|
||||
},
|
||||
"raw": [{"oid": "1.2.3.4", "critical": False, "der_hex": "0c03616263"}],
|
||||
},
|
||||
}
|
||||
response = await client.post(f"/api/vaults/{vault_id}/certificates/preview", json=payload)
|
||||
assert response.status_code == 200, response.text
|
||||
names = [row["name"] for row in response.json()["extensions"]]
|
||||
assert "CRL Distribution Points" in names
|
||||
assert "Authority Information Access" in names
|
||||
|
||||
@async_test
|
||||
async def test_mandatory_dn_and_no_expiration(self) -> None:
|
||||
async with api_client() as client:
|
||||
with oidc_user("alice"):
|
||||
vault_id = await _vault(client)
|
||||
settings = (await client.get(f"/api/vaults/{vault_id}/settings")).json()
|
||||
await client.patch(
|
||||
f"/api/vaults/{vault_id}/settings",
|
||||
json={"settings": {"mandatory_dn": ["CN"]}, "version": settings["version"]},
|
||||
)
|
||||
key = await _key(client, vault_id)
|
||||
now = datetime.now(timezone.utc)
|
||||
response = await client.post(
|
||||
f"/api/vaults/{vault_id}/certificates",
|
||||
json={
|
||||
"name": "missing cn",
|
||||
"key_id": key["id"],
|
||||
"subject": [{"name": "O", "value": "KCA"}],
|
||||
"validity": {"amount": 1, "unit": "days"},
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert "mandatory" in response.json()["error"]
|
||||
response = await client.post(
|
||||
f"/api/vaults/{vault_id}/certificates",
|
||||
json={
|
||||
"name": "forever",
|
||||
"key_id": key["id"],
|
||||
"subject": _subject("forever"),
|
||||
"validity": {"no_expiration": True},
|
||||
},
|
||||
)
|
||||
assert response.status_code == 201, response.text
|
||||
assert response.json()["no_expiration"] is True
|
||||
|
||||
@async_test
|
||||
async def test_ca_template_and_revocation_edit(self) -> None:
|
||||
async with api_client() as client:
|
||||
with oidc_user("alice"):
|
||||
vault_id = await _vault(client)
|
||||
ca_key = await _key(client, vault_id, "ca")
|
||||
ca = await _cert(client, vault_id, ca_key["id"], "CA", ca=True)
|
||||
response = await client.patch(
|
||||
f"/api/vaults/{vault_id}/certificates/{ca['id']}/ca",
|
||||
json={"crl_days": 45, "template_id": "builtin:tls-server"},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["default_template"] == "builtin:tls-server"
|
||||
assert response.json()["crl_days"] == 45
|
||||
response = await client.post(
|
||||
f"/api/vaults/{vault_id}/certificates/{ca['id']}/revocations",
|
||||
json={"serial_hex": "1234", "reason": "keyCompromise", "invalidity_date": datetime.now(timezone.utc).isoformat()},
|
||||
)
|
||||
assert response.status_code == 201, response.text
|
||||
rev = response.json()
|
||||
response = await client.patch(
|
||||
f"/api/vaults/{vault_id}/certificates/{ca['id']}/revocations/{rev['id']}",
|
||||
json={"reason": "superseded", "invalidity_date": None},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["reason"] == "superseded"
|
||||
|
||||
|
||||
class VaultExportTests(unittest.TestCase):
|
||||
@async_test
|
||||
async def test_vault_zip_export(self) -> None:
|
||||
import io
|
||||
import zipfile
|
||||
async with api_client() as client:
|
||||
with oidc_user("alice"):
|
||||
vault_id = await _vault(client)
|
||||
key = await _key(client, vault_id, "zip key")
|
||||
cert = await _cert(client, vault_id, key["id"], "Zip Cert", ca=True)
|
||||
response = await client.post(f"/api/vaults/{vault_id}/export", json={"password": "secret"})
|
||||
assert response.status_code == 200, response.text
|
||||
payload = response.json()
|
||||
data = base64.b64decode(payload["content_base64"])
|
||||
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
||||
names = archive.namelist()
|
||||
assert "manifest.json" in names
|
||||
assert any(name.startswith("certificates/") for name in names)
|
||||
assert any(name.startswith("keys/") for name in names)
|
||||
manifest = archive.read("manifest.json")
|
||||
assert b"Zip Cert" in manifest
|
||||
|
||||
Reference in New Issue
Block a user