improved error and log messages
authorTony Mack <tmack@paris.CS.Princeton.EDU>
Fri, 26 Aug 2011 17:01:54 +0000 (13:01 -0400)
committerTony Mack <tmack@paris.CS.Princeton.EDU>
Fri, 26 Aug 2011 17:01:54 +0000 (13:01 -0400)
sfa/trust/certificate.py
sfa/trust/credential.py
sfa/trust/gid.py

index 13f8975..8cbe172 100644 (file)
@@ -480,6 +480,7 @@ class Certificate:
         else:\r
             setattr(subj, "CN", name)\r
         self.cert.set_subject(subj)\r
+\r
     ##\r
     # Get the subject name of the certificate\r
 \r
@@ -487,6 +488,13 @@ class Certificate:
         x = self.cert.get_subject()\r
         return getattr(x, which)\r
 \r
+    ##\r
+    # Get a pretty-print subject name of the certificate\r
+\r
+    def get_printable_subject(self):\r
+        x = self.cert.get_subject()\r
+        return "[ OU: %s, CN: %s, SubjectAltName: %s ]" % (getattr(x, "OU"), getattr(x, "CN"), self.get_data())\r
+\r
     ##\r
     # Get the public key of the certificate.\r
     #\r
@@ -689,31 +697,31 @@ class Certificate:
 \r
         # verify expiration time\r
         if self.cert.has_expired():\r
-            logger.debug("verify_chain: NO our certificate has expired")\r
-            raise CertExpired(self.get_subject(), "client cert")   \r
-        \r
+            logger.debug("verify_chain: NO our certificate %s has expired" % self.get_printable_subject())\r
+            raise CertExpired(self.get_printable_subject(), "client cert")\r
+\r
         # if this cert is signed by a trusted_cert, then we are set\r
         for trusted_cert in trusted_certs:\r
             if self.is_signed_by_cert(trusted_cert):\r
                 # verify expiration of trusted_cert ?\r
                 if not trusted_cert.cert.has_expired():\r
                     logger.debug("verify_chain: YES cert %s signed by trusted cert %s"%(\r
-                            self.get_subject(), trusted_cert.get_subject()))\r
+                            self.get_printable_subject(), trusted_cert.get_printable_subject()))\r
                     return trusted_cert\r
                 else:\r
                     logger.debug("verify_chain: NO cert %s is signed by trusted_cert %s, but this is expired..."%(\r
-                            self.get_subject(),trusted_cert.get_subject()))\r
-                    raise CertExpired(self.get_subject(),"trusted_cert %s"%trusted_cert.get_subject())\r
+                            self.get_printable_subject(),trusted_cert.get_printable_subject()))\r
+                    raise CertExpired(self.get_printable_subject()," signer trusted_cert %s"%trusted_cert.get_printable_subject())\r
 \r
         # if there is no parent, then no way to verify the chain\r
         if not self.parent:\r
-            logger.debug("verify_chain: NO %s has no parent and is not in trusted roots"%self.get_subject())\r
-            raise CertMissingParent(self.get_subject())\r
+            logger.debug("verify_chain: NO %s has no parent and issuer %s is not in %d trusted roots"%self.get_printable_subject(), self.get_issuer(), len(trusted_certs))\r
+            raise CertMissingParent(self.get_printable_subject(), "Non trusted issuer: %s out of %d trusted roots" % (self.get_issuer(), len(trusted_certs)))\r
 \r
         # if it wasn't signed by the parent...\r
         if not self.is_signed_by_cert(self.parent):\r
-            logger.debug("verify_chain: NO %s is not signed by parent"%self.get_subject())\r
-            return CertNotSignedByParent(self.get_subject())\r
+            logger.debug("verify_chain: NO %s is not signed by parent %s, but by %s"%self.get_printable_subject(), self.parent.get_printable_subject(), self.get_issuer())\r
+            return CertNotSignedByParent(self.get_printable_subject(), "parent %s, issuer %s" % (selr.parent.get_printable_subject(), self.get_issuer()))\r
 \r
         # Confirm that the parent is a CA. Only CAs can be trusted as\r
         # signers.\r
@@ -722,11 +730,11 @@ class Certificate:
         # Ugly - cert objects aren't parsed so we need to read the\r
         # extension and hope there are no other basicConstraints\r
         if not self.parent.isCA and not (self.parent.get_extension('basicConstraints') == 'CA:TRUE'):\r
-            logger.warn("verify_chain: cert %s's parent %s is not a CA" % (self.get_subject(), self.parent.get_subject()))\r
-            return CertNotSignedByParent(self.get_subject())\r
+            logger.warn("verify_chain: cert %s's parent %s is not a CA" % (self.get_printable_subject(), self.parent.get_printable_subject()))\r
+            return CertNotSignedByParent(self.get_printable_subject(), "Parent %s not a CA" % self.parent.get_printable_subject())\r
 \r
         # if the parent isn't verified...\r
-        logger.debug("verify_chain: .. %s, -> verifying parent %s"%(self.get_subject(),self.parent.get_subject()))\r
+        logger.debug("verify_chain: .. %s, -> verifying parent %s"%(self.get_printable_subject(),self.parent.get_printable_subject()))\r
         self.parent.verify_chain(trusted_certs)\r
 \r
         return\r
@@ -761,7 +769,7 @@ class Certificate:
 \r
     def dump_string (self,show_extensions=False):\r
         result = ""\r
-        result += "CERTIFICATE for %s\n"%self.get_subject()\r
+        result += "CERTIFICATE for %s\n"%self.get_printable_subject()\r
         result += "Issued by %s\n"%self.get_issuer()\r
         filename=self.get_filename()\r
         if filename: result += "Filename %s\n"%filename\r
index 3480a72..f112a95 100644 (file)
@@ -269,7 +269,16 @@ class Credential(object):
     def get_subject(self):\r
         if not self.gidObject:\r
             self.decode()\r
-        return self.gidObject.get_subject()   \r
+        return self.gidObject.get_printable_subject()\r
+\r
+    def get_summary_tostring(self):\r
+        if not self.gidObject:\r
+            self.decode()\r
+        obj = self.gidObject.get_printable_subject()\r
+        caller = self.gidCaller.get_printable_subject()\r
+        exp = self.get_expiration()\r
+        # Summarize the rights too? The issuer?\r
+        return "[ Grant %s rights on %s until %s ]" % (caller, obj, exp)\r
 \r
     def get_signature(self):\r
         if not self.signature:\r
@@ -672,13 +681,19 @@ class Credential(object):
 \r
         # Is this a signed-cred or just a cred?\r
         if len(signed_cred) > 0:\r
-            cred = signed_cred[0].getElementsByTagName("credential")[0]\r
+            creds = signed_cred[0].getElementsByTagName("credential")\r
             signatures = signed_cred[0].getElementsByTagName("signatures")\r
             if len(signatures) > 0:\r
                 sigs = signatures[0].getElementsByTagName("Signature")\r
         else:\r
-            cred = doc.getElementsByTagName("credential")[0]\r
+            creds = doc.getElementsByTagName("credential")\r
         \r
+        if creds is None or len(creds) == 0:\r
+            # malformed cred file\r
+            raise CredentialNotVerifiable("Malformed XML: No credential tag found")\r
+\r
+        # Just take the first cred if there are more than one\r
+        cred = creds[0]\r
 \r
         self.set_refid(cred.getAttribute("xml:id"))\r
         self.set_expiration(utcparse(getTextNode(cred, "expires")))\r
@@ -765,7 +780,7 @@ class Credential(object):
                 xmlschema = etree.XMLSchema(schema_doc)\r
                 if not xmlschema.validate(tree):\r
                     error = xmlschema.error_log.last_error\r
-                    message = "%s (line %s)" % (error.message, error.line)\r
+                    message = "%s: %s (line %s)" % (self.get_summary_tostring(), error.message, error.line)\r
                     raise CredentialNotVerifiable(message)\r
 \r
         if trusted_certs_required and trusted_certs is None:\r
@@ -798,7 +813,7 @@ class Credential(object):
         \r
         # make sure it is not expired\r
         if self.get_expiration() < datetime.datetime.utcnow():\r
-            raise CredentialNotVerifiable("Credential expired at %s" % self.expiration.isoformat())\r
+            raise CredentialNotVerifiable("Credential %s expired at %s" % (self.get_summary_tostring(), self.expiration.isoformat()))\r
 \r
         # Verify the signatures\r
         filename = self.save_to_random_tmp_file()\r
@@ -838,7 +853,7 @@ class Credential(object):
                     mstart = mstart + 4\r
                     mend = verified.find('\\', mstart)\r
                     msg = verified[mstart:mend]\r
-                raise CredentialNotVerifiable("xmlsec1 error verifying cred using Signature ID %s: %s %s" % (ref, msg, verified.strip()))\r
+                raise CredentialNotVerifiable("xmlsec1 error verifying cred %s using Signature ID %s: %s %s" % (self.get_summary_tostring(), ref, msg, verified.strip()))\r
         os.remove(filename)\r
 \r
         # Verify the parents (delegation)\r
@@ -944,23 +959,23 @@ class Credential(object):
         # make sure the rights given to the child are a subset of the\r
         # parents rights (and check delegate bits)\r
         if not parent_cred.get_privileges().is_superset(self.get_privileges()):\r
-            raise ChildRightsNotSubsetOfParent(("Parent cred ref %s rights " % self.parent.get_refid()) + \r
-                self.parent.get_privileges().save_to_string() + (" not superset of delegated cred ref %s rights " % self.get_refid()) +\r
+            raise ChildRightsNotSubsetOfParent(("Parent cred ref %s rights " % parent_cred.get_refid()) +\r
+                self.parent.get_privileges().save_to_string() + (" not superset of delegated cred %s ref %s rights " % (self.get_summary_tostring(), self.get_refid())) +\r
                 self.get_privileges().save_to_string())\r
 \r
         # make sure my target gid is the same as the parent's\r
         if not parent_cred.get_gid_object().save_to_string() == \\r
            self.get_gid_object().save_to_string():\r
-            raise CredentialNotVerifiable("Target gid not equal between parent and child")\r
+            raise CredentialNotVerifiable("Delegated cred %s: Target gid not equal between parent and child. Parent %s" % (self.get_summary_tostring(), parent_cred.get_summary_tostring()))\r
 \r
         # make sure my expiry time is <= my parent's\r
         if not parent_cred.get_expiration() >= self.get_expiration():\r
-            raise CredentialNotVerifiable("Delegated credential expires after parent")\r
+            raise CredentialNotVerifiable("Delegated credential %s expires after parent %s" % (self.get_summary_tostring(), parent_cred.get_summary_tostring()))\r
 \r
         # make sure my signer is the parent's caller\r
         if not parent_cred.get_gid_caller().save_to_string(False) == \\r
            self.get_signature().get_issuer_gid().save_to_string(False):\r
-            raise CredentialNotVerifiable("Delegated credential not signed by parent caller")\r
+            raise CredentialNotVerifiable("Delegated credential %s not signed by parent %s's caller" % (self.get_summary_tostring(), parent_cred.get_summary_tostring()))\r
                 \r
         # Recurse\r
         if parent_cred.parent:\r
index b327c0c..a7b2e71 100644 (file)
@@ -212,7 +212,7 @@ class GID(Certificate):
         if self.parent:\r
             # make sure the parent's hrn is a prefix of the child's hrn\r
             if not hrn_authfor_hrn(self.parent.get_hrn(), self.get_hrn()):\r
-                raise GidParentHrn("This cert HRN %s isn't in the namespace for  parent HRN %s" % (self.get_hrn(), self.parent.get_hrn()))\r
+                raise GidParentHrn("This cert HRN %s isn't in the namespace for parent HRN %s" % (self.get_hrn(), self.parent.get_hrn()))\r
 \r
             # Parent must also be an authority (of some type) to sign a GID\r
             # There are multiple types of authority - accept them all here\r