+
+ ##
+ # Retrieve the attributes of the credential from the XML.
+ # This is automatically called by the various get_* methods of
+ # this class and should not need to be called explicitly.
+
+ def decode(self):
+ if not self.xml:
+ return
+ doc = parseString(self.xml)
+ sigs = []
+ signed_cred = doc.getElementsByTagName("signed-credential")
+
+ # Is this a signed-cred or just a cred?
+ if len(signed_cred) > 0:
+ cred = signed_cred[0].getElementsByTagName("credential")[0]
+ signatures = signed_cred[0].getElementsByTagName("signatures")
+ if len(signatures) > 0:
+ sigs = signatures[0].getElementsByTagName("Signature")
+ else:
+ cred = doc.getElementsByTagName("credential")[0]
+
+
+
+ self.set_refid(cred.getAttribute("xml:id"))
+ self.set_lifetime(parse(getTextNode(cred, "expires")))
+ self.gidCaller = GID(string=getTextNode(cred, "owner_gid"))
+ self.gidObject = GID(string=getTextNode(cred, "target_gid"))
+
+
+ # Process privileges
+ privs = cred.getElementsByTagName("privileges")[0]
+ rlist = RightList()
+ for priv in privs.getElementsByTagName("privilege"):
+ kind = getTextNode(priv, "name")
+ deleg = str2bool(getTextNode(priv, "can_delegate"))
+ if kind == '*':
+ # Convert * into the default privileges for the credential's type
+ _ , type = urn_to_hrn(self.gidObject.get_urn())
+ rl = rlist.determine_rights(type, self.gidObject.get_urn())
+ for r in rl.rights:
+ rlist.add(r)
+ else:
+ rlist.add(Right(kind.strip(), deleg))
+ self.set_privileges(rlist)
+
+
+ # Is there a parent?
+ parent = cred.getElementsByTagName("parent")
+ if len(parent) > 0:
+ parent_doc = parent[0].getElementsByTagName("credential")[0]
+ parent_xml = parent_doc.toxml()
+ self.parent = Credential(string=parent_xml)
+ self.updateRefID()
+
+ # Assign the signatures to the credentials
+ for sig in sigs:
+ Sig = Signature(string=sig.toxml())
+
+ for cur_cred in self.get_credential_list():
+ if cur_cred.get_refid() == Sig.get_refid():
+ cur_cred.set_signature(Sig)
+
+
+ ##
+ # Verify
+ # trusted_certs: A list of trusted GID filenames (not GID objects!)
+ # Chaining is not supported within the GIDs by xmlsec1.
+ #
+ # Verify that:
+ # . All of the signatures are valid and that the issuers trace back
+ # to trusted roots (performed by xmlsec1)
+ # . The XML matches the credential schema
+ # . That the issuer of the credential is the authority in the target's urn
+ # . In the case of a delegated credential, this must be true of the root
+ # . That all of the gids presented in the credential are valid
+ # . The credential is not expired
+ #
+ # -- For Delegates (credentials with parents)
+ # . The privileges must be a subset of the parent credentials
+ # . The privileges must have "can_delegate" set for each delegated privilege
+ # . The target gid must be the same between child and parents
+ # . The expiry time on the child must be no later than the parent
+ # . The signer of the child must be the owner of the parent
+ #
+ # -- Verify does *NOT*
+ # . ensure that an xmlrpc client's gid matches a credential gid, that
+ # must be done elsewhere
+ #
+ # @param trusted_certs: The certificates of trusted CA certificates
+
+ def verify(self, trusted_certs):
+ if not self.xml:
+ self.decode()
+ trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
+
+ # Use legacy verification if this is a legacy credential
+ if self.legacy:
+ self.legacy.verify_chain(trusted_cert_objects)
+ if self.legacy.client_gid:
+ self.legacy.client_gid.verify_chain(trusted_cert_objects)
+ 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_lifetime() < datetime.datetime.utcnow():
+ raise CredentialNotVerifiable("credential is expired")
+
+ # Verify the signatures
+ filename = self.save_to_random_tmp_file()
+ cert_args = " ".join(['--trusted-pem %s' % x for x in trusted_certs])
+
+ # Verify the gids of this cred and of its parents
+
+
+
+ for cur_cred in self.get_credential_list():
+ cur_cred.get_gid_object().verify_chain(trusted_cert_objects)
+ cur_cred.get_gid_caller().verify_chain(trusted_cert_objects)
+
+
+ refs = []
+ refs.append("Sig_%s" % self.get_refid())
+
+ parentRefs = self.updateRefID()
+ for ref in parentRefs:
+ refs.append("Sig_%s" % ref)
+
+ for ref in refs:
+ verified = os.popen('%s --verify --node-id "%s" %s %s 2>&1' \
+ % (self.xmlsec_path, ref, cert_args, filename)).read()
+ if not verified.strip().startswith("OK"):
+ raise CredentialNotVerifiable("xmlsec1 error: " + verified)
+ os.remove(filename)
+
+ # Verify the parents (delegation)