aboutsummaryrefslogtreecommitdiff
path: root/rpki/rpkidb/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpki/rpkidb/models.py')
-rw-r--r--rpki/rpkidb/models.py259
1 files changed, 179 insertions, 80 deletions
diff --git a/rpki/rpkidb/models.py b/rpki/rpkidb/models.py
index d3bbbfa5..1f61a982 100644
--- a/rpki/rpkidb/models.py
+++ b/rpki/rpkidb/models.py
@@ -279,10 +279,16 @@ class Tenant(models.Model):
booleans = ("use_hsm",),
elements = ("bpki_cert", "bpki_glue"))
+ def __repr__(self):
+ try:
+ return "<Tenant: {}>".format(self.tenant_handle)
+ except:
+ return "<Tenant: Tenant object>"
+
@tornado.gen.coroutine
def xml_pre_delete_hook(self, rpkid):
trace_call_chain()
- yield [parent.destroy() for parent in self.parents.all()]
+ yield [parent.destroy(rpkid = rpkid) for parent in self.parents.all()]
@tornado.gen.coroutine
def xml_post_save_hook(self, rpkid, q_pdu):
@@ -327,49 +333,42 @@ class Tenant(models.Model):
trace_call_chain()
publisher = rpki.rpkid.publication_queue(rpkid = rpkid)
- repositories = set()
objects = dict()
- for parent in self.parents.all():
-
- repository = parent.repository
- if repository.peer_contact_uri in repositories:
- continue
- repositories.add(repository.peer_contact_uri)
+ for repository in self.repositories.all():
q_msg = Element(rpki.publication.tag_msg, nsmap = rpki.publication.nsmap,
type = "query", version = rpki.publication.version)
SubElement(q_msg, rpki.publication.tag_list, tag = "list")
-
r_msg = yield repository.call_pubd(rpkid, q_msg, length_check = False)
-
- for r_pdu in r_msg:
- assert r_pdu.tag == rpki.publication.tag_list
- if r_pdu.get("uri") in objects:
- logger.warning("pubd reported multiple published copies of URI %r, this makes no sense, blundering onwards", r_pdu.get("uri"))
- else:
- objects[r_pdu.get("uri")] = (r_pdu.get("hash"), repository)
-
- def reconcile(uri, obj, repository):
- h, r = objects.pop(uri, (None, None))
- if h is not None:
- assert r == repository
- publisher.queue(uri = uri, new_obj = obj, old_hash = h, repository = repository)
+ if not all(r_pdu.tag == rpki.publication.tag_list for r_pdu in r_msg):
+ raise rpki.exceptions.BadPublicationReply("Unexpected XML tag in publication response")
+ objs = dict((r_pdu.get("uri"), (r_pdu.get("hash"), repository))
+ for r_pdu in r_msg if r_pdu.tag == rpki.publication.tag_list)
+ if any(uri in objects for uri in objs):
+ for uri in sorted(set(objects) & set(objs)):
+ logger.warning("Duplicated publication URI %s between %r and %r, this should not happen",
+ uri, objects[uri][1], objs[uri][1])
+ objects.update(objs)
for ca_detail in CADetail.objects.filter(ca__parent__tenant = self, state = "active"):
repository = ca_detail.ca.parent.repository
- reconcile(uri = ca_detail.crl_uri, obj = ca_detail.latest_crl, repository = repository)
- reconcile(uri = ca_detail.manifest_uri, obj = ca_detail.latest_manifest, repository = repository)
- for c in ca_detail.child_certs.all():
- reconcile(uri = c.uri, obj = c.cert, repository = repository)
- for r in ca_detail.roas.filter(roa__isnull = False):
- reconcile(uri = r.uri, obj = r.roa, repository = repository)
- for g in ca_detail.ghostbusters.all():
- reconcile(uri = g.uri, obj = g.ghostbuster, repository = repository)
- for c in ca_detail.ee_certificates.all():
- reconcile(uri = c.uri, obj = c.cert, repository = repository)
- for u in objects:
- h, r = objects[u]
- publisher.queue(uri = u, old_hash = h, repository = r)
+ objs = [(ca_detail.crl_uri, ca_detail.latest_crl),
+ (ca_detail.manifest_uri, ca_detail.latest_manifest)]
+ objs.extend((c.uri, c.cert) for c in ca_detail.child_certs.all())
+ objs.extend((r.uri, r.roa) for r in ca_detail.roas.filter(roa__isnull = False))
+ objs.extend((g.uri, g.ghostbuster) for g in ca_detail.ghostbusters.all())
+ objs.extend((c.uri, c.cert) for c in ca_detail.ee_certificates.all())
+ for uri, obj in objs:
+ h, r = objects.get(uri, (None, None))
+ if uri in objects and r == repository:
+ publisher.queue(uri = uri, new_obj = obj, repository = repository, old_hash = h)
+ del objects[uri]
+ else:
+ publisher.queue(uri = uri, new_obj = obj, repository = repository)
+
+ for u in objects:
+ h, r = objects[u]
+ publisher.queue(uri = u, old_hash = h, repository = r)
yield publisher.call_pubd()
@@ -377,7 +376,7 @@ class Tenant(models.Model):
@tornado.gen.coroutine
def serve_run_now(self, rpkid):
trace_call_chain()
- logger.debug("Forced immediate run of periodic actions for tenant %s[%r]", self.tenant_handle, self)
+ logger.debug("Forced immediate run of periodic actions for %r", self)
tasks = self.cron_tasks(rpkid = rpkid)
rpkid.task_add(tasks)
futures = [task.wait() for task in tasks]
@@ -432,6 +431,11 @@ class BSC(models.Model):
elements = ("signing_cert", "signing_cert_crl"),
readonly = ("pkcs10_request",))
+ def __repr__(self):
+ try:
+ return "<BSC: {}.{}>".format(self.tenant.tenant_handle, self.bsc_handle)
+ except:
+ return "<BSC: BSC object>"
def xml_pre_save_hook(self, q_pdu):
# Handle key generation, only supports RSA with SHA-256 for now.
@@ -462,6 +466,16 @@ class Repository(models.Model):
attributes = ("peer_contact_uri", "rrdp_notification_uri"),
elements = ("bpki_cert", "bpki_glue"))
+ def __repr__(self):
+ try:
+ uri = " " + self.peer_contact_uri
+ except:
+ uri = ""
+ try:
+ return "<Repository: {}.{}{}>".format(self.tenant.tenant_handle, self.repository_handle, uri)
+ except:
+ return "<Repository: Repository object>"
+
@tornado.gen.coroutine
def xml_post_save_hook(self, rpkid, q_pdu):
@@ -496,7 +510,7 @@ class Repository(models.Model):
if len(q_msg) == 0:
return
if handlers is None:
- handlers = {}
+ handlers = {}
for q_pdu in q_msg:
logger.info("Sending %r hash = %s uri = %s to pubd", q_pdu, q_pdu.get("hash"), q_pdu.get("uri"))
http_request = tornado.httpclient.HTTPRequest(
@@ -547,11 +561,21 @@ class Parent(models.Model):
attributes = ("peer_contact_uri", "sia_base", "sender_name", "recipient_name"),
elements = ("bpki_cert", "bpki_glue"))
+ def __repr__(self):
+ try:
+ uri = " " + self.peer_contact_uri
+ except:
+ uri = ""
+ try:
+ return "<Parent: {}.{}{}>".format(self.tenant.tenant_handle, self.parent_handle, uri)
+ except:
+ return "<Parent: Parent object>"
+
@tornado.gen.coroutine
def xml_pre_delete_hook(self, rpkid):
trace_call_chain()
- yield self.destroy(rpkid, delete_parent = False)
+ yield self.destroy(rpkid = rpkid, delete_parent = False)
@tornado.gen.coroutine
def xml_post_save_hook(self, rpkid, q_pdu):
@@ -659,7 +683,7 @@ class Parent(models.Model):
"""
trace_call_chain()
- yield [ca.destroy(self) for ca in self.cas()] # pylint: disable=E1101
+ yield [ca.destroy(rpkid = rpkid, parent = self) for ca in self.cas()] # pylint: disable=E1101
yield self.serve_revoke_forgotten(rpkid = rpkid)
if delete_parent:
self.delete()
@@ -710,7 +734,7 @@ class Parent(models.Model):
if self.bsc is None:
raise rpki.exceptions.BSCNotFound("Could not find BSC")
if self.bsc.signing_cert is None:
- raise rpki.exceptions.BSCNotReady("BSC %r is not yet usable" % self.bsc.bsc_handle)
+ raise rpki.exceptions.BSCNotReady("%r is not yet usable" % self.bsc)
http_request = tornado.httpclient.HTTPRequest(
url = self.peer_contact_uri,
method = "POST",
@@ -761,9 +785,9 @@ class CA(models.Model):
# response; if not present, we'd use parent's class_name as now,
# otherwise we'd use the supplied class_name.
- # ca_obj has a zillion properties encoding various specialized
- # ca_detail queries. ORM query syntax probably renders this OBE,
- # but need to translate in existing code.
+ # ca_obj had a zillion properties encoding various specialized
+ # ca_detail queries. ORM query syntax renders this OBE, but need
+ # to translate in existing code.
#
#def pending_ca_details(self): return self.ca_details.filter(state = "pending")
#def active_ca_detail(self): return self.ca_details.get(state = "active")
@@ -772,6 +796,15 @@ class CA(models.Model):
#def revoked_ca_details(self): return self.ca_details.filter(state = "revoked")
#def issue_response_candidate_ca_details(self): return self.ca_details.exclude(state = "revoked")
+ def __repr__(self):
+ try:
+ return "<CA: {}.{} class {}>".format(self.parent.tenant.tenant_handle,
+ self.parent.parent_handle,
+ self.parent_resource_class)
+ except:
+ return "<CA: CA object>"
+
+
@tornado.gen.coroutine
def destroy(self, rpkid, parent):
"""
@@ -792,9 +825,9 @@ class CA(models.Model):
try:
yield publisher.call_pubd()
except:
- logger.exception("Could not delete CA %r, skipping", self)
+ logger.exception("Could not destroy %r, skipping", self)
else:
- logger.debug("Deleting %r", self)
+ logger.debug("Destroying %r", self)
self.delete()
@@ -844,7 +877,7 @@ class CA(models.Model):
logger.debug("Sending issue request to %r from %r", self.parent, self.rekey)
r_msg = yield self.parent.up_down_issue_query(rpkid = rpkid, ca = self, ca_detail = new_detail)
c = r_msg[0][0]
- logger.debug("CA %r received certificate %s", self, c.get("cert_url"))
+ logger.debug("%r received certificate %s", self, c.get("cert_url"))
yield new_detail.activate(
rpkid = rpkid,
ca = self,
@@ -944,6 +977,16 @@ class CADetail(models.Model):
ca_cert_uri = models.TextField(null = True)
ca = models.ForeignKey(CA, related_name = "ca_details") # pylint: disable=C0103
+ def __repr__(self):
+ try:
+ return "<CADetail: {}.{} class {} {} {}>".format(self.ca.parent.tenant.tenant_handle,
+ self.ca.parent.parent_handle,
+ self.ca.parent_resource_class,
+ self.state,
+ self.ca_cert_uri)
+ except:
+ return "<CADetail: CADetail object>"
+
@property
def crl_uri(self):
@@ -1067,7 +1110,7 @@ class CADetail(models.Model):
cert = rpki.x509.X509(Base64 = c.text)
cert_url = c.get("cert_url")
- logger.debug("CA %r received certificate %s", self, cert_url)
+ logger.debug("%r received certificate %s", self, cert_url)
if self.state == "pending":
yield self.activate(rpkid = rpkid, ca = ca, cert = cert, uri = cert_url)
@@ -1386,6 +1429,12 @@ class Child(models.Model):
handles = (BSC,),
elements = ("bpki_cert", "bpki_glue"))
+ def __repr__(self):
+ try:
+ return "<Child: {}.{}>".format(self.tenant.tenant_handle, self.child_handle)
+ except:
+ return "<Child: Child object>"
+
@tornado.gen.coroutine
def xml_pre_delete_hook(self, rpkid):
@@ -1570,6 +1619,14 @@ class ChildCert(models.Model):
child = models.ForeignKey(Child, related_name = "child_certs")
ca_detail = models.ForeignKey(CADetail, related_name = "child_certs")
+ def __repr__(self):
+ try:
+ return "<ChildCert: {}.{} {}>".format(self.child.tenant.tenant_handle,
+ self.child.child_handle,
+ self.uri)
+ except:
+ return "<ChildCert: ChildCert object>"
+
@property
def uri_tail(self):
@@ -1596,7 +1653,7 @@ class ChildCert(models.Model):
trace_call_chain()
ca_detail = self.ca_detail
- logger.debug("Revoking %r %r", self, self.uri)
+ logger.debug("Revoking %r", self)
RevokedCert.revoke(cert = self.cert, ca_detail = ca_detail)
publisher.queue(uri = self.uri, old_obj = self.cert, repository = ca_detail.ca.parent.repository)
self.delete()
@@ -1606,12 +1663,13 @@ class ChildCert(models.Model):
def reissue(self, ca_detail, publisher, resources = None, sia = None, force = False):
"""
- Reissue an existing child cert, reusing the public key. If the
- child cert we would generate is identical to the one we already
- have, we just return the one we already have. If we have to
- revoke the old child cert when generating the new one, we have to
- generate a new child_cert_obj, so calling code that needs the
- updated child_cert_obj must use the return value from this method.
+ Reissue an existing child cert, reusing the public key. If
+ the child cert we would generate is identical to the one we
+ already have, we just return the one we already have. If we
+ have to revoke the old child cert when generating the new one,
+ we have to generate a new ChildCert, so calling code that
+ needs the updated ChildCert must use the return value from
+ this method.
"""
trace_call_chain()
@@ -1656,7 +1714,7 @@ class ChildCert(models.Model):
return self
if must_revoke:
for child_cert in child.child_certs.filter(ca_detail = ca_detail, gski = self.gski):
- logger.debug("Revoking child_cert %r", child_cert)
+ logger.debug("Revoking %r", child_cert)
child_cert.revoke(publisher = publisher)
ca_detail.generate_crl_and_manifest(publisher = publisher)
child_cert = ca_detail.issue(
@@ -1667,7 +1725,7 @@ class ChildCert(models.Model):
resources = resources,
child_cert = None if must_revoke else self,
publisher = publisher)
- logger.debug("New child_cert %r uri %s", child_cert, child_cert.uri)
+ logger.debug("New %r", child_cert)
return child_cert
@@ -1689,11 +1747,18 @@ class EECertificate(models.Model):
tenant = models.ForeignKey(Tenant, related_name = "ee_certificates")
ca_detail = models.ForeignKey(CADetail, related_name = "ee_certificates")
+ def __repr__(self):
+ try:
+ return "<EECertificate: {} {}>".format(self.tenant.tenant_handle,
+ self.uri)
+ except:
+ return "<EECertificate: EECertificate object>"
+
@property
def uri(self):
"""
- Return the publication URI for this ee_cert_obj.
+ Return the publication URI for this EECertificate.
"""
return self.ca_detail.ca.sia_uri + self.uri_tail
@@ -1703,7 +1768,7 @@ class EECertificate(models.Model):
def uri_tail(self):
"""
Return the tail (filename portion) of the publication URI for this
- ee_cert_obj.
+ EECertificate.
"""
return self.gski + ".cer"
@@ -1716,7 +1781,7 @@ class EECertificate(models.Model):
trace_call_chain()
ca_detail = self.ca_detail
- logger.debug("Revoking %r %r", self, self.uri)
+ logger.debug("Revoking %r", self)
RevokedCert.revoke(cert = self.cert, ca_detail = ca_detail)
publisher.queue(uri = self.uri, old_obj = self.cert, repository = ca_detail.ca.parent.repository)
self.delete()
@@ -1728,7 +1793,7 @@ class EECertificate(models.Model):
"""
Reissue an existing EE cert, reusing the public key. If the EE
cert we would generate is identical to the one we already have, we
- just return; if we need to reissue, we reuse this ee_cert_obj and
+ just return; if we need to reissue, we reuse this EECertificate and
just update its contents, as the publication URI will not have
changed.
"""
@@ -1809,10 +1874,20 @@ class Ghostbuster(models.Model):
tenant = models.ForeignKey(Tenant, related_name = "ghostbusters")
ca_detail = models.ForeignKey(CADetail, related_name = "ghostbusters")
+ def __repr__(self):
+ try:
+ uri = " " + self.uri
+ except:
+ uri = ""
+ try:
+ return "<Ghostbuster: {}{}>".format(self.tenant.tenant_handle, uri)
+ except:
+ return "<Ghostbuster: Ghostbuster object>"
+
def update(self, publisher, fast = False):
"""
- Bring this ghostbuster_obj up to date if necesssary.
+ Bring this Ghostbuster up to date if necesssary.
"""
trace_call_chain()
@@ -1861,7 +1936,7 @@ class Ghostbuster(models.Model):
self.ghostbuster = rpki.x509.Ghostbuster.build(self.vcard, keypair, (self.cert,))
self.published = rpki.sundial.now()
self.save()
- logger.debug("Generating Ghostbuster record %r", self.uri)
+ logger.debug("Generating %r", self)
publisher.queue(
uri = self.uri,
new_obj = self.ghostbuster,
@@ -1884,7 +1959,7 @@ class Ghostbuster(models.Model):
def revoke(self, publisher, regenerate = False, allow_failure = False, fast = False):
"""
- Withdraw Ghostbuster associated with this ghostbuster_obj.
+ Withdraw Ghostbuster associated with this Ghostbuster.
In order to preserve make-before-break properties without
duplicating code, this method also handles generating a
@@ -1900,12 +1975,10 @@ class Ghostbuster(models.Model):
trace_call_chain()
ca_detail = self.ca_detail
- logger.debug("%s %r, ca_detail %r state is %s",
- "Regenerating" if regenerate else "Not regenerating",
- self, ca_detail, ca_detail.state)
+ logger.debug("%s %r", "Regenerating" if regenerate else "Not regenerating", self)
if regenerate:
self.generate(publisher = publisher, fast = fast)
- logger.debug("Withdrawing %r %s and revoking its EE cert", self, self.uri)
+ logger.debug("Withdrawing %r and revoking its EE cert", self)
RevokedCert.revoke(cert = self.cert, ca_detail = ca_detail)
publisher.queue(uri = self.uri,
old_obj = self.ghostbuster,
@@ -1919,7 +1992,7 @@ class Ghostbuster(models.Model):
def regenerate(self, publisher, fast = False):
"""
- Reissue Ghostbuster associated with this ghostbuster_obj.
+ Reissue Ghostbuster associated with this Ghostbuster.
"""
trace_call_chain()
@@ -1941,7 +2014,7 @@ class Ghostbuster(models.Model):
@property
def uri(self):
"""
- Return the publication URI for this ghostbuster_obj's ghostbuster.
+ Return the publication URI for this Ghostbuster.
"""
return self.ca_detail.ca.sia_uri + self.uri_tail
@@ -1951,7 +2024,7 @@ class Ghostbuster(models.Model):
def uri_tail(self):
"""
Return the tail (filename portion) of the publication URI for this
- ghostbuster_obj's ghostbuster.
+ Ghostbuster.
"""
return self.cert.gSKI() + ".gbr"
@@ -1963,6 +2036,20 @@ class RevokedCert(models.Model):
expires = SundialField()
ca_detail = models.ForeignKey(CADetail, related_name = "revoked_certs")
+ def __repr__(self):
+ try:
+ return "<RevokedCert: {}.{} class {} {} serial {} revoked {} expires {}>".format(
+ self.ca_detail.ca.parent.tenant.tenant_handle,
+ self.ca_detail.ca.parent.parent_handle,
+ self.ca_detail.ca.parent_resource_class,
+ self.ca_detail.crl_uri,
+ self.serial,
+ self.revoked,
+ self.expires)
+ except:
+ return "<RevokedCert: RevokedCert object>"
+
+
@classmethod
def revoke(cls, cert, ca_detail):
"""
@@ -1987,6 +2074,20 @@ class ROA(models.Model):
tenant = models.ForeignKey(Tenant, related_name = "roas")
ca_detail = models.ForeignKey(CADetail, related_name = "roas")
+ def __repr__(self):
+ try:
+ resources = " " + ",".join(str(ip) for ip in (self.ipv4, self.ipv6) if ip is not None)
+ except:
+ resources = ""
+ try:
+ uri = " " + self.uri
+ except:
+ uri = ""
+ try:
+ return "<ROA: {}{}{}>".format(self.tenant.tenant_handle, resources, uri)
+ except:
+ return "<ROA: ROA object>"
+
def update(self, publisher, fast = False):
"""
@@ -2079,7 +2180,7 @@ class ROA(models.Model):
for ca_detail in CADetail.objects.filter(ca__parent__tenant = self.tenant, state = "active"):
resources = ca_detail.latest_ca_cert.get_3779resources()
if not ca_detail.has_expired() and v4.issubset(resources.v4) and v6.issubset(resources.v6):
- logger.debug("Using new ca_detail %r for ROA %r", ca_detail, self)
+ logger.debug("Using %r for ROA %r", ca_detail, self)
self.ca_detail = ca_detail
break
else:
@@ -2101,7 +2202,7 @@ class ROA(models.Model):
self.published = rpki.sundial.now()
self.save()
- logger.debug("Generating %r URI %s", self, self.uri)
+ logger.debug("Generating %r", self)
publisher.queue(uri = self.uri, new_obj = self.roa,
repository = self.ca_detail.ca.parent.repository,
handler = self.published_callback)
@@ -2122,7 +2223,7 @@ class ROA(models.Model):
def revoke(self, publisher, regenerate = False, allow_failure = False, fast = False):
"""
- Withdraw ROA associated with this roa_obj.
+ Withdraw this ROA.
In order to preserve make-before-break properties without
duplicating code, this method also handles generating a
@@ -2138,12 +2239,10 @@ class ROA(models.Model):
trace_call_chain()
ca_detail = self.ca_detail
- logger.debug("%s %r, ca_detail %r state is %s",
- "Regenerating" if regenerate else "Not regenerating",
- self, ca_detail, ca_detail.state)
+ logger.debug("%s %r", "Regenerating" if regenerate else "Not regenerating", self)
if regenerate:
self.generate(publisher = publisher, fast = fast)
- logger.debug("Withdrawing %r %s and revoking its EE cert", self, self.uri)
+ logger.debug("Withdrawing %r and revoking its EE cert", self)
RevokedCert.revoke(cert = self.cert, ca_detail = ca_detail)
publisher.queue(uri = self.uri, old_obj = self.roa,
repository = ca_detail.ca.parent.repository,
@@ -2156,7 +2255,7 @@ class ROA(models.Model):
def regenerate(self, publisher, fast = False):
"""
- Reissue ROA associated with this roa_obj.
+ Reissue this ROA.
"""
trace_call_chain()
@@ -2178,7 +2277,7 @@ class ROA(models.Model):
@property
def uri(self):
"""
- Return the publication URI for this roa_obj's ROA.
+ Return the publication URI for this ROA.
"""
return self.ca_detail.ca.sia_uri + self.uri_tail
@@ -2188,7 +2287,7 @@ class ROA(models.Model):
def uri_tail(self):
"""
Return the tail (filename portion) of the publication URI for this
- roa_obj's ROA.
+ ROA.
"""
return self.cert.gSKI() + ".roa"