From a9a76ebe68611ff68c24d772f3e2d354858b1bf0 Mon Sep 17 00:00:00 2001 From: Josh Karlin Date: Wed, 31 Mar 2010 20:45:20 +0000 Subject: [PATCH] Improvements to the XML based credential, still no verification --- sfa/client/sfi.py | 11 +- sfa/managers/registry_manager_pl.py | 2 +- sfa/plc/api.py | 2 +- sfa/trust/credential.py | 191 ++++++++++++++++------------ sfa/trust/hierarchy.py | 8 +- 5 files changed, 132 insertions(+), 82 deletions(-) diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 0e3b8121..4187446d 100755 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -8,6 +8,7 @@ import os, os.path import tempfile import traceback import socket +import random from types import StringTypes, ListType from optparse import OptionParser from sfa.trust.certificate import Keypair, Certificate @@ -478,7 +479,15 @@ class Sfi: dcred.set_privileges(user_cred.get_privileges()) dcred.set_delegate(True) dcred.set_pubkey(object_gid.get_pubkey()) - dcred.set_issuer(user_key, user_cred.get_gid_caller()) + + # Save the issuer's gid to a file + fname = self.options.sfi_dir + os.sep + "gid_%d" % random.randint(0,999999999) + f = open(fname, "w") + f.write(user_cred.get_gid_caller().save_to_string()) + f.close() + dcred.set_issuer_keys(self.get_key_file(), fname) + os.remove(fname) + dcred.set_parent(user_cred) dcred.encode() dcred.sign() diff --git a/sfa/managers/registry_manager_pl.py b/sfa/managers/registry_manager_pl.py index 03462ee5..e7690a21 100644 --- a/sfa/managers/registry_manager_pl.py +++ b/sfa/managers/registry_manager_pl.py @@ -55,7 +55,7 @@ def get_credential(api, xrn, type, is_self=False): new_cred = Credential(subject = object_gid.get_subject()) new_cred.set_gid_caller(caller_gid) new_cred.set_gid_object(object_gid) - new_cred.set_issuer_keys(auth_info.get_pkey_object(), auth_info.get_gid_object()) + new_cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename()) new_cred.set_pubkey(object_gid.get_pubkey()) new_cred.set_privileges(rights) new_cred.set_delegate(True) diff --git a/sfa/plc/api.py b/sfa/plc/api.py index 4cb05b13..a5aa9217 100644 --- a/sfa/plc/api.py +++ b/sfa/plc/api.py @@ -153,7 +153,7 @@ class SfaAPI(BaseAPI): new_cred = Credential(subject = object_gid.get_subject()) new_cred.set_gid_caller(object_gid) new_cred.set_gid_object(object_gid) - new_cred.set_issuer_keys(auth_info.get_pkey_object(), auth_info.get_gid_object()) + new_cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename()) new_cred.set_pubkey(object_gid.get_pubkey()) r1 = determine_rights(type, hrn) new_cred.set_privileges(r1) diff --git a/sfa/trust/credential.py b/sfa/trust/credential.py index 5b27d2d4..e8fc7030 100644 --- a/sfa/trust/credential.py +++ b/sfa/trust/credential.py @@ -23,35 +23,12 @@ from sfa.util.faults import * from sfa.util.sfalogging import * -signed_cred_template = \ -''' - - %s - - - %s - - -''' - - -credential_template = \ -''' - - privilege - 8 - %s - %s - %s - %s - - %s - - %s - - -''' - +# TODO: +# . Need to verify credentials +# . Need to add privileges +# . Need to fix lifetime +# . Need to make sure delegation is fully supported +# . Need to test signature_template = \ ''' @@ -92,13 +69,13 @@ signature_template = \ # are placed in signed XML. -class Credential(Certificate): +class Credential(object): gidCaller = None gidObject = None lifeTime = None privileges = None delegate = False - issuer_key = None + issuer_privkey = None issuer_gid = None issuer_pubkey = None parent = None @@ -116,14 +93,17 @@ class Credential(Certificate): # Check if this is a legacy credential, translate it if so if string or filename: - if str: + if string: str = string elif filename: str = file(filename).read() if str.strip().startswith("-----"): self.translate_legacy(str) - + else: + self.xml = str + # Let's not mess around with invalid credentials + self.verify_chain() ## # Translate a legacy credential into a new one @@ -131,13 +111,12 @@ class Credential(Certificate): # @param String of the legacy credential def translate_legacy(self, str): - legacy = CredentialLegacy(create, subject, string, filename) + legacy = CredentialLegacy(False,string=str) self.gidCaller = legacy.get_gid_caller() self.gidObject = legacy.get_gid_object() self.lifeTime = legacy.get_lifetime() self.privileges = legacy.get_privileges() self.delegate = legacy.get_delegate() - self.encode() ## # Need the issuer's private key and name @@ -145,7 +124,7 @@ class Credential(Certificate): # @param gid GID of the issuing authority def set_issuer_keys(self, privkey, gid): - self.issuer_key = privkey + self.issuer_privkey = privkey self.issuer_gid = gid def set_pubkey(self, pubkey): @@ -252,7 +231,9 @@ class Credential(Certificate): return rights.can_perform(op_name) def append_sub(self, doc, parent, element, text): - parent.appendChild(doc.createElement(element).appendChild(doc.createTextNode(text))) + ele = doc.createElement(element) + ele.appendChild(doc.createTextNode(text)) + parent.appendChild(ele) ## # Encode the attributes of the credential into an XML string @@ -275,17 +256,18 @@ class Credential(Certificate): # Fill in the bit + refid = "ref1" cred = doc.createElement("credential") cred.setAttribute("xml:id", refid) signed_cred.appendChild(cred) self.append_sub(doc, cred, "type", "privilege") self.append_sub(doc, cred, "serial", "8") - self.append_sub(doc, cred, "owner_gid", cur_cred.gidCaller.save_to_string()) - self.append_sub(doc, cred, "owner_urn", cur_cred.gidCaller.get_urn()) - self.append_sub(doc, cred, "target_gid", cur_cred.gidObject.save_to_string()) - self.append_sub(doc, cred, "target_urn", cur_cred.gidObject.get_urn()) + self.append_sub(doc, cred, "owner_gid", self.gidCaller.save_to_string()) + self.append_sub(doc, cred, "owner_urn", self.gidCaller.get_urn()) + self.append_sub(doc, cred, "target_gid", self.gidObject.save_to_string()) + self.append_sub(doc, cred, "target_urn", self.gidObject.get_urn()) self.append_sub(doc, cred, "uuid", "") - self.append_sub(doc, cred, "expires", self.lifeTime) + self.append_sub(doc, cred, "expires", str(self.lifeTime)) priveleges = doc.createElement("privileges") cred.appendChild(priveleges) @@ -307,7 +289,7 @@ class Credential(Certificate): sz_sig = signature_template % (refid,refid) sdoc = xml.dom.minidom.parseString(sz_sig) - sig_ele = doc.importNode(sdoc.getElemenetsByTagName("Signature")[0], True) + sig_ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True) signatures.appendChild(sig_ele) @@ -316,56 +298,109 @@ class Credential(Certificate): for sig in p_sigs: signatures.appendChild(sig) + signed_cred.appendChild(signatures) # Get the finished product self.xml = doc.toxml() + #print doc.toprettyxml() + -## # Call out to xmlsec1 to sign it -## XMLSEC = '/usr/bin/xmlsec1' -## filename = "/tmp/cred_%d" % random.random() -## f = open(filename, "w") -## f.write(whole); -## f.close() -## signed = os.popen('/usr/bin/xmlsec1 --sign --node-id "%s" --privkey-pem %s,%s %s' -## % ('ref1', self.issuer_privkey, self.issuer_cert, filename)).readlines() -## os.rm(filename) + def save_to_string(self): + if not self.xml: + self.encode() + return self.xml -## self.encoded = signed + def sign(self): + if not self.xml: + self.encode() + # Call out to xmlsec1 to sign it + XMLSEC = '/usr/bin/xmlsec1' + + filename = "/tmp/cred_%d" % random.randint(0,999999999) + f = open(filename, "w") + f.write(self.xml); + f.close() + signed = os.popen('/usr/bin/xmlsec1 --sign --node-id "%s" --privkey-pem %s,%s %s' \ + % ('ref1', self.issuer_privkey, self.issuer_gid, filename)).read() + os.remove(filename) + + self.xml = signed + + def getTextNode(self, element, subele): + sub = element.getElementsByTagName(subele)[0] + return sub.childNodes[0].nodeValue + ## - # Retrieve the attributes of the credential from the alt-subject-name field - # of the X509 certificate. This is automatically done by the various - # get_* methods of this class and should not need to be called explicitly. + # Retrieve the attributes of the credential from the XML. + # This is automatically caleld by the various get_* methods of + # this class and should not need to be called explicitly. def decode(self): - data = self.get_data().lstrip('URI:http://') + p_doc = xml.dom.minidom.parseString(self.xml) + p_signed_cred = p_doc.getElementsByTagName("signed-credential")[0] + p_cred = p_signed_cred.getElementsByTagName("credential")[0] + p_signatures = p_signed_cred.getElementsByTagName("signatures")[0] + p_sigs = p_signatures.getElementsByTagName("Signature") + + self.lifeTime = self.getTextNode(p_cred, "expires") + self.gidCaller = GID(string=self.getTextNode(p_cred, "owner_gid")) + self.gidObject = GID(string=self.getTextNode(p_cred, "target_gid")) - if data: - dict = xmlrpclib.loads(data)[0][0] - else: - dict = {} + + +## ## +## # Retrieve the attributes of the credential from the alt-subject-name field +## # of the X509 certificate. This is automatically done by the various +## # get_* methods of this class and should not need to be called explicitly. - self.lifeTime = dict.get("lifeTime", None) - self.delegate = dict.get("delegate", None) +## def decode(self): +## data = self.get_data().lstrip('URI:http://') + +## if data: +## dict = xmlrpclib.loads(data)[0][0] +## else: +## dict = {} - privStr = dict.get("privileges", None) - if privStr: - self.privileges = RightList(string = privStr) - else: - self.privileges = None +## self.lifeTime = dict.get("lifeTime", None) +## self.delegate = dict.get("delegate", None) - gidCallerStr = dict.get("gidCaller", None) - if gidCallerStr: - self.gidCaller = GID(string=gidCallerStr) - else: - self.gidCaller = None +## privStr = dict.get("privileges", None) +## if privStr: +## self.privileges = RightList(string = privStr) +## else: +## self.privileges = None + +## gidCallerStr = dict.get("gidCaller", None) +## if gidCallerStr: +## self.gidCaller = GID(string=gidCallerStr) +## else: +## self.gidCaller = None + +## gidObjectStr = dict.get("gidObject", None) +## if gidObjectStr: +## self.gidObject = GID(string=gidObjectStr) +## else: +## self.gidObject = None + + + ## + # Verify for the initial credential: + # 1. That the signature is valid + # 2. That the xml signer's certificate matches the object's certificate + # 3. That the urns match those in the gids + # + # Verify for the delegated credentials: + # 1. That the signature is valid + + # 4. + # 3. That the object's certificate stays the s + # 2. That the GID of the + + def verify(self, trusted_certs = None): + - gidObjectStr = dict.get("gidObject", None) - if gidObjectStr: - self.gidObject = GID(string=gidObjectStr) - else: - self.gidObject = None ## # Verify that a chain of credentials is valid (see cert.py:verify). In diff --git a/sfa/trust/hierarchy.py b/sfa/trust/hierarchy.py index d6839318..3f0580fe 100644 --- a/sfa/trust/hierarchy.py +++ b/sfa/trust/hierarchy.py @@ -60,6 +60,12 @@ class AuthInfo: self.gid_filename = fn self.gid_object = None + def get_privkey_filename(self): + return self.privkey_filename + + def get_gid_filename(self): + return self.gid_filename + ## # Get the GID in the form of a GID object @@ -307,7 +313,7 @@ class Hierarchy: else: # we need the parent's private key in order to sign this GID parent_auth_info = self.get_auth_info(parent_hrn) - cred.set_issuer(parent_auth_info.get_pkey_object(), parent_auth_info.get_gid_object()) + cred.set_issuer(parent_auth_info.get_privkey_filename(), parent_auth_info.get_gid_filename()) cred.set_parent(self.get_auth_cred(parent_hrn, kind)) cred.encode() -- 2.47.0