really fixed the redundant logging issue this time.
[sfa.git] / sfa / trust / credential.py
index b46a655..3e1fbcc 100644 (file)
 # Credentials are signed XML files that assign a subject gid privileges to an object gid
 ##
 
-### $Id$
-### $URL$
-
 import os
 import datetime
 from tempfile import mkstemp
+import dateutil.parser
+from StringIO import StringIO 
 from xml.dom.minidom import Document, parseString
-from dateutil.parser import parse
+from lxml import etree
 
 from sfa.util.faults import *
-from sfa.util.sfalogging import sfa_logger
+from sfa.util.sfalogging import logger
 from sfa.trust.certificate import Keypair
 from sfa.trust.credential_legacy import CredentialLegacy
 from sfa.trust.rights import Right, Rights
 from sfa.trust.gid import GID
-from sfa.util.namespace import *
+from sfa.util.xrn import urn_to_hrn
 
 # 2 weeks, in seconds 
 DEFAULT_CREDENTIAL_LIFETIME = 86400 * 14
@@ -82,7 +81,7 @@ signature_template = \
 # Convert a string into a bool
 
 def str2bool(str):
-    if str.lower() in ['yes','true','1']:
+    if str.lower() in ['true','1']:
         return True
     return False
 
@@ -215,6 +214,7 @@ class Credential(object):
                 str = string
             elif filename:
                 str = file(filename).read()
+                self.filename=filename
                 
             if str.strip().startswith("-----"):
                 self.legacy = CredentialLegacy(False,string=str)
@@ -452,6 +452,7 @@ class Credential(object):
             f = open(filename, "w")
         f.write(self.xml)
         f.close()
+        self.filename=filename
 
     def save_to_string(self, save_parents=True):
         if not self.xml:
@@ -582,7 +583,7 @@ class Credential(object):
         
 
         self.set_refid(cred.getAttribute("xml:id"))
-        self.set_expiration(parse(getTextNode(cred, "expires")))
+        self.set_expiration(dateutil.parser.parse(getTextNode(cred, "expires")))
         self.gidCaller = GID(string=getTextNode(cred, "owner_gid"))
         self.gidObject = GID(string=getTextNode(cred, "target_gid"))   
 
@@ -647,11 +648,24 @@ class Credential(object):
     #   must be done elsewhere
     #
     # @param trusted_certs: The certificates of trusted CA certificates
-    def verify(self, trusted_certs):
+    # @param schema: The RelaxNG schema to validate the credential against 
+    def verify(self, trusted_certs, schema=None):
         if not self.xml:
             self.decode()        
+        
+        # validate against RelaxNG schema
+        if not self.legacy:
+            if schema and os.path.exists(schema):
+                tree = etree.parse(StringIO(self.xml))
+                schema_doc = etree.parse(schema)
+                xmlschema = etree.XMLSchema(schema_doc)
+                if not xmlschema.validate(tree):
+                    error = xmlschema.error_log.last_error
+                    message = "%s (line %s)" % (error.message, error.line)
+                    raise CredentialNotVerifiable(message) 
+            
 
-#        trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
+#       trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
         trusted_cert_objects = []
         ok_trusted_certs = []
         for f in trusted_certs:
@@ -661,7 +675,7 @@ class Credential(object):
                 trusted_cert_objects.append(GID(filename=f))
                 ok_trusted_certs.append(f)
             except Exception, exc:
-                sfa_logger.error("Failed to load trusted cert from %s: %r", f, exc)
+                logger.error("Failed to load trusted cert from %s: %r"%( f, exc))
         trusted_certs = ok_trusted_certs
 
         # Use legacy verification if this is a legacy credential
@@ -672,6 +686,7 @@ class Credential(object):
             if self.legacy.object_gid:
                 self.legacy.object_gid.verify_chain(trusted_cert_objects)
             return True
+
         
         # make sure it is not expired
         if self.get_expiration() < datetime.datetime.utcnow():
@@ -744,7 +759,7 @@ class Credential(object):
         # Maybe should be (hrn, type) = urn_to_hrn(root_cred_signer.get_urn())
         root_cred_signer_type = root_cred_signer.get_type()
         if (root_cred_signer_type == 'authority'):
-            #sfa_logger.debug('Cred signer is an authority')
+            #logger.debug('Cred signer is an authority')
             # signer is an authority, see if target is in authority's domain
             hrn = root_cred_signer.get_hrn()
             if root_target_gid.get_hrn().startswith(hrn):
@@ -824,28 +839,38 @@ class Credential(object):
         dcred.sign()
 
         return dcred 
-    ##
-    # Dump the contents of a credential to stdout in human-readable format
-    #
-    # @param dump_parents If true, also dump the parent certificates
-
-    def dump(self, dump_parents=False):
-        print "CREDENTIAL", self.get_subject()
 
-        print "      privs:", self.get_privileges().save_to_string()
+    # only informative
+    def get_filename(self):
+        return getattr(self,'filename',None)
 
-        print "  gidCaller:"
+    # @param dump_parents If true, also dump the parent certificates
+    def dump (self, *args, **kwargs):
+        print self.dump_string(*args, **kwargs)
+
+    def dump_string(self, dump_parents=False):
+        result=""
+        result += "CREDENTIAL %s\n" % self.get_subject() 
+        filename=self.get_filename()
+        if filename: result += "Filename %s\n"%filename
+        result += "      privs: %s\n" % self.get_privileges().save_to_string()
         gidCaller = self.get_gid_caller()
         if gidCaller:
-            gidCaller.dump(8, dump_parents)
+            result += "  gidCaller:\n"
+            result += gidCaller.dump_string(8, dump_parents)
+
+        if self.get_signature():
+            print "  gidIssuer:"
+            self.get_signature().get_issuer_gid().dump(8, dump_parents)
 
-        print "  gidObject:"
         gidObject = self.get_gid_object()
         if gidObject:
-            gidObject.dump(8, dump_parents)
-
+            result += "  gidObject:\n"
+            result += gidObject.dump_string(8, dump_parents)
 
         if self.parent and dump_parents:
-            print "PARENT",
-            self.parent.dump_parents()
+            result += "\nPARENT"
+            result += self.parent.dump(True)
+
+        return result