+ rights = self.get_privileges()
+ for right in rights.rights:
+ priv = doc.createElement("privilege")
+ append_sub(doc, priv, "name", right.kind)
+ append_sub(doc, priv, "can_delegate", str(right.delegate).lower())
+ privileges.appendChild(priv)
+
+ # Add the parent credential if it exists
+ if self.parent:
+ sdoc = parseString(self.parent.get_xml())
+ # If the root node is a signed-credential (it should be), then
+ # get all its attributes and attach those to our signed_cred
+ # node.
+ # Specifically, PG and PLadd attributes for namespaces (which is reasonable),
+ # and we need to include those again here or else their signature
+ # no longer matches on the credential.
+ # We expect three of these, but here we copy them all:
+# signed_cred.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
+# and from PG (PL is equivalent, as shown above):
+# signed_cred.setAttribute("xsi:noNamespaceSchemaLocation", "http://www.protogeni.net/resources/credential/credential.xsd")
+# signed_cred.setAttribute("xsi:schemaLocation", "http://www.protogeni.net/resources/credential/ext/policy/1 http://www.protogeni.net/resources/credential/ext/policy/1/policy.xsd")
+
+ # HOWEVER!
+ # PL now also declares these, with different URLs, so
+ # the code notices those attributes already existed with
+ # different values, and complains.
+ # This happens regularly on delegation now that PG and
+ # PL both declare the namespace with different URLs.
+ # If the content ever differs this is a problem,
+ # but for now it works - different URLs (values in the attributes)
+ # but the same actual schema, so using the PG schema
+ # on delegated-to-PL credentials works fine.
+
+ # Note: you could also not copy attributes
+ # which already exist. It appears that both PG and PL
+ # will actually validate a slicecred with a parent
+ # signed using PG namespaces and a child signed with PL
+ # namespaces over the whole thing. But I don't know
+ # if that is a bug in xmlsec1, an accident since
+ # the contents of the schemas are the same,
+ # or something else, but it seems odd. And this works.
+ parentRoot = sdoc.documentElement
+ if parentRoot.tagName == "signed-credential" and parentRoot.hasAttributes():
+ for attrIx in range(0, parentRoot.attributes.length):
+ attr = parentRoot.attributes.item(attrIx)
+ # returns the old attribute of same name that was
+ # on the credential
+ # Below throws InUse exception if we forgot to clone the attribute first
+ oldAttr = signed_cred.setAttributeNode(attr.cloneNode(True))
+ if oldAttr and oldAttr.value != attr.value:
+ msg = "Delegating cred from owner %s to %s over %s replaced attribute %s value '%s' with '%s'" % (self.parent.gidCaller.get_urn(), self.gidCaller.get_urn(), self.gidObject.get_urn(), oldAttr.name, oldAttr.value, attr.value)
+ logger.warn(msg)
+ #raise CredentialNotVerifiable("Can't encode new valid delegated credential: %s" % msg)
+
+ p_cred = doc.importNode(sdoc.getElementsByTagName("credential")[0], True)
+ p = doc.createElement("parent")
+ p.appendChild(p_cred)
+ cred.appendChild(p)
+ # done handling parent credential
+
+ # Create the <signatures> tag
+ signatures = doc.createElement("signatures")
+ signed_cred.appendChild(signatures)
+
+ # Add any parent signatures
+ if self.parent:
+ for cur_cred in self.get_credential_list()[1:]:
+ sdoc = parseString(cur_cred.get_signature().get_xml())
+ ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
+ signatures.appendChild(ele)
+
+ # Get the finished product
+ self.xml = doc.toxml()
+
+
+ def save_to_random_tmp_file(self):
+ fp, filename = mkstemp(suffix='cred', text=True)
+ fp = os.fdopen(fp, "w")
+ self.save_to_file(filename, save_parents=True, filep=fp)
+ return filename
+
+ def save_to_file(self, filename, save_parents=True, filep=None):
+ if not self.xml:
+ self.encode()
+ if filep:
+ f = filep
+ else:
+ f = open(filename, "w")
+ f.write(self.xml)
+ f.close()
+
+ def save_to_string(self, save_parents=True):
+ if not self.xml:
+ self.encode()
+ return self.xml
+
+ def get_refid(self):
+ if not self.refid:
+ self.refid = 'ref0'
+ return self.refid
+
+ def set_refid(self, rid):
+ self.refid = rid
+
+ ##
+ # Figure out what refids exist, and update this credential's id
+ # so that it doesn't clobber the others. Returns the refids of
+ # the parents.
+
+ def updateRefID(self):
+ if not self.parent:
+ self.set_refid('ref0')
+ return []
+
+ refs = []
+
+ next_cred = self.parent
+ while next_cred:
+ refs.append(next_cred.get_refid())
+ if next_cred.parent:
+ next_cred = next_cred.parent
+ else:
+ next_cred = None
+
+
+ # Find a unique refid for this credential
+ rid = self.get_refid()
+ while rid in refs:
+ val = int(rid[3:])
+ rid = "ref%d" % (val + 1)
+
+ # Set the new refid
+ self.set_refid(rid)
+
+ # Return the set of parent credential ref ids
+ return refs
+
+ def get_xml(self):
+ if not self.xml:
+ self.encode()
+ return self.xml