Beispiel #1
0
    def delegate(self, delegee_gidfile, caller_keyfile, caller_gidfile):
        """
        Return a delegated copy of this credential, delegated to the 
        specified gid's user.    
        """
        # get the gid of the object we are delegating
        object_gid = self.get_gid_object()
        object_hrn = object_gid.get_hrn()        
 
        # the hrn of the user who will be delegated to
        delegee_gid = GID(filename=delegee_gidfile)
        delegee_hrn = delegee_gid.get_hrn()
  
        #user_key = Keypair(filename=keyfile)
        #user_hrn = self.get_gid_caller().get_hrn()
        subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
        dcred = Credential(subject=subject_string)
        dcred.set_gid_caller(delegee_gid)
        dcred.set_gid_object(object_gid)
        dcred.set_parent(self)
        dcred.set_expiration(self.get_expiration())
        dcred.set_privileges(self.get_privileges())
        dcred.get_privileges().delegate_all_privileges(True)
        #dcred.set_issuer_keys(keyfile, delegee_gidfile)
        dcred.set_issuer_keys(caller_keyfile, caller_gidfile)
        dcred.encode()
        dcred.sign()

        return dcred
Beispiel #2
0
    def decode(self):
        data = self.get_data().lstrip('URI:http://')

        if data:
            dict = xmlrpclib.loads(data)[0][0]
        else:
            dict = {}

        self.lifeTime = dict.get("lifeTime", None)
        self.delegate = dict.get("delegate", None)

        privStr = dict.get("privileges", None)
        if privStr:
            self.privileges = Rights(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
Beispiel #3
0
    def sign(self):
        if not self.issuer_privkey:
            return
        if not self.issuer_gid:
            return
        doc = parseString(self.get_xml())
        sigs = doc.getElementsByTagName("signatures")[0]

        # Create the signature template to be signed
        signature = Signature()
        signature.set_refid(self.get_refid())
        sdoc = parseString(signature.get_xml())        
        sig_ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
        sigs.appendChild(sig_ele)

        self.xml = doc.toxml("utf-8")


        # Split the issuer GID into multiple certificates if it's a chain
        chain = GID(filename=self.issuer_gid)
        gid_files = []
        while chain:
            gid_files.append(chain.save_to_random_tmp_file(False))
            if chain.get_parent():
                chain = chain.get_parent()
            else:
                chain = None


        # Call out to xmlsec1 to sign it
        ref = 'Sig_%s' % self.get_refid()
        filename = self.save_to_random_tmp_file()
        print "**********************************",'%s --sign --node-id "%s" --privkey-pem %s,%s %s' % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)
        command='%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
            % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)
#        print 'command',command
        signed = os.popen(command).read()
        print "*************************************",signed
        os.remove(filename)

        for gid_file in gid_files:
            os.remove(gid_file)

        self.xml = signed

        # This is no longer a legacy credential
        if self.legacy:
            self.legacy = None

        # Update signatures
        self.decode()       
Beispiel #4
0
    def verify(self, trusted_certs=None, schema=None, trusted_certs_required=True):
        if not self.xml:
            print "\n\n\n\n\n\n\n\n\n\n\n\n\n----------------------CRED\n\n\n\n\n\n\n\n\n\n\n\n\n"
            print "not xml"
            self.decode()

        # validate against RelaxNG schema
        if HAVELXML and 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: %s (line %s)" % (self.get_summary_tostring(), error.message, error.line)
                    raise CredentialNotVerifiable(message)

        if trusted_certs_required and trusted_certs is None:
            trusted_certs = []

#        trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
        trusted_cert_objects = []
        ok_trusted_certs = []
        # If caller explicitly passed in None that means skip cert chain validation.
        # Strange and not typical
        if trusted_certs is not None:
            for f in trusted_certs:
                try:
                    # Failures here include unreadable files
                    # or non PEM files
                    trusted_cert_objects.append(GID(filename=f))
                    ok_trusted_certs.append(f)
                except Exception, exc:
                    pass
            trusted_certs = ok_trusted_certs
Beispiel #5
0
    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:
            creds = signed_cred[0].getElementsByTagName("credential")
            signatures = signed_cred[0].getElementsByTagName("signatures")
            if len(signatures) > 0:
                sigs = signatures[0].getElementsByTagName("Signature")
        else:
            creds = doc.getElementsByTagName("credential")
        
        if creds is None or len(creds) == 0:
            # malformed cred file
            raise CredentialNotVerifiable("Malformed XML: No credential tag found")

        # Just take the first cred if there are more than one
        cred = creds[0]

        self.set_refid(cred.getAttribute("xml:id"))
        self.set_expiration(utcparse(getTextNode(cred, "expires")))

#        import traceback
#        stack = traceback.extract_stack()

        og = getTextNode(cred, "owner_gid")
        # ABAC creds will have this be None and use this method
#        if og is None:
#            found = False
#            for frame in stack:
#                if 'super(ABACCredential, self).decode()' in frame:
#                    found = True
#                    break
#            if not found:
#                raise CredentialNotVerifiable("Malformed XML: No owner_gid found")
        self.gidCaller = GID(string=og)
        tg = getTextNode(cred, "target_gid")
#        if tg is None:
#            found = False
#            for frame in stack:
#                if 'super(ABACCredential, self).decode()' in frame:
#                    found = True
#                    break
#            if not found:
#                raise CredentialNotVerifiable("Malformed XML: No target_gid found")
        self.gidObject = GID(string=tg)

        # Process privileges
        rlist = Rights()
        priv_nodes = cred.getElementsByTagName("privileges")
        if len(priv_nodes) > 0:
            privs = priv_nodes[0]
            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
                    # Each inherits the delegatability from the * above
                    _ , type = urn_to_hrn(self.gidObject.get_urn())
                    rl = determine_rights(type, self.gidObject.get_urn())
                    for r in rl.rights:
                        r.delegate = deleg
                        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("utf-8")
            if parent_xml is None or parent_xml.strip() == "":
                raise CredentialNotVerifiable("Malformed XML: Had parent tag but it is empty")
            self.parent = Credential(string=parent_xml)
            self.updateRefID()

        # Assign the signatures to the credentials
        for sig in sigs:
            Sig = Signature(string=sig.toxml("utf-8"))

            for cur_cred in self.get_credential_list():
                if cur_cred.get_refid() == Sig.get_refid():
                    cur_cred.set_signature(Sig)
Beispiel #6
0
class Credential(object):

    SFA_CREDENTIAL_TYPE = "geni_sfa"

    ##
    # Create a Credential object
    #
    # @param create If true, create a blank x509 certificate
    # @param subject If subject!=None, create an x509 cert with the subject name
    # @param string If string!=None, load the credential from the string
    # @param filename If filename!=None, load the credential from the file
    # FIXME: create and subject are ignored!
    def __init__(self, create=False, subject=None, string=None, filename=None):
        self.gidCaller = None
        self.gidObject = None
        self.expiration = None
        self.privileges = None
        self.issuer_privkey = None
        self.issuer_gid = None
        self.issuer_pubkey = None
        self.parent = None
        self.signature = None
        self.xml = None
        self.refid = None
        self.legacy = None
        self.cred_type = Credential.SFA_CREDENTIAL_TYPE

        # Check if this is a legacy credential, translate it if so
        if string or filename:
            if string:                
                str = string
            elif filename:
                str = file(filename).read()
                
            if str.strip().startswith("-----"):
                self.legacy = CredentialLegacy(False,string=str)
                self.translate_legacy(str)
            else:
                self.xml = str
                self.decode()

        # Find an xmlsec1 path
        self.xmlsec_path = ''
        paths = ['/usr/bin','/usr/local/bin','/bin','/opt/bin','/opt/local/bin']
        for path in paths:
            if os.path.isfile(path + '/' + 'xmlsec1'):
                self.xmlsec_path = path + '/' + 'xmlsec1'
                break
        if not self.xmlsec_path:
            pass

    def get_cred_type(self): 
        return self.cred_type

    def get_subject(self):
        if not self.gidObject:
            self.decode()
        return self.gidObject.get_subject()

    # sounds like this should be __repr__ instead ??
    def get_summary_tostring(self):
        if not self.gidObject:
            self.decode()
        obj = self.gidObject.get_printable_subject()
        caller = self.gidCaller.get_printable_subject()
        exp = self.get_expiration()
        # Summarize the rights too? The issuer?
        return "[ Grant %s rights on %s until %s ]" % (caller, obj, exp)

    def get_signature(self):
        if not self.signature:
            self.decode()
        return self.signature

    def set_signature(self, sig):
        self.signature = sig

        
    ##
    # Translate a legacy credential into a new one
    #
    # @param String of the legacy credential

    def translate_legacy(self, str):
        legacy = CredentialLegacy(False,string=str)
        self.gidCaller = legacy.get_gid_caller()
        self.gidObject = legacy.get_gid_object()
        lifetime = legacy.get_lifetime()
        if not lifetime:
            self.set_expiration(datetime.datetime.utcnow() + datetime.timedelta(seconds=DEFAULT_CREDENTIAL_LIFETIME))
        else:
            self.set_expiration(int(lifetime))
        self.lifeTime = legacy.get_lifetime()
        self.set_privileges(legacy.get_privileges())
        self.get_privileges().delegate_all_privileges(legacy.get_delegate())

    ##
    # Need the issuer's private key and name
    # @param key Keypair object containing the private key of the issuer
    # @param gid GID of the issuing authority

    def set_issuer_keys(self, privkey, gid):
        self.issuer_privkey = privkey
        self.issuer_gid = gid


    ##
    # Set this credential's parent
    def set_parent(self, cred):
        self.parent = cred
        self.updateRefID()

    ##
    # set the GID of the caller
    #
    # @param gid GID object of the caller

    def set_gid_caller(self, gid):
        self.gidCaller = gid
        # gid origin caller is the caller's gid by default
        self.gidOriginCaller = gid

    ##
    # get the GID of the object

    def get_gid_caller(self):
        if not self.gidCaller:
            self.decode()
        return self.gidCaller

    ##
    # set the GID of the object
    #
    # @param gid GID object of the object

    def set_gid_object(self, gid):
        self.gidObject = gid

    ##
    # get the GID of the object

    def get_gid_object(self):
        if not self.gidObject:
            self.decode()
        return self.gidObject
            
    ##
    # Expiration: an absolute UTC time of expiration (as either an int or string or datetime)
    # 
    def set_expiration(self, expiration):
        if isinstance(expiration, (int, float)):
            self.expiration = datetime.datetime.fromtimestamp(expiration)
        elif isinstance (expiration, datetime.datetime):
            self.expiration = expiration
        elif isinstance (expiration, StringTypes):
            self.expiration = utcparse (expiration)
        else:
            pass


    ##
    # get the lifetime of the credential (always in datetime format)

    def get_expiration(self):
        if not self.expiration:
            self.decode()
        # at this point self.expiration is normalized as a datetime - DON'T call utcparse again
        return self.expiration

    ##
    # For legacy sake
    def get_lifetime(self):
        return self.get_expiration()
 
    ##
    # set the privileges
    #
    # @param privs either a comma-separated list of privileges of a Rights object

    def set_privileges(self, privs):
        if isinstance(privs, str):
            self.privileges = Rights(string = privs)
        else:
            self.privileges = privs        

    ##
    # return the privileges as a Rights object

    def get_privileges(self):
        if not self.privileges:
            self.decode()
        return self.privileges

    ##
    # determine whether the credential allows a particular operation to be
    # performed
    #
    # @param op_name string specifying name of operation ("lookup", "update", etc)

    def can_perform(self, op_name):
        rights = self.get_privileges()
        
        if not rights:
            return False

        return rights.can_perform(op_name)


    ##
    # Encode the attributes of the credential into an XML string    
    # This should be done immediately before signing the credential.    
    # WARNING:
    # In general, a signed credential obtained externally should
    # not be changed else the signature is no longer valid.  So, once
    # you have loaded an existing signed credential, do not call encode() or sign() on it.

    def encode(self):
        # Create the XML document
        doc = Document()
        signed_cred = doc.createElement("signed-credential")

# Declare namespaces
# Note that credential/policy.xsd are really the PG schemas
# in a PL namespace.
# Note that delegation of credentials between the 2 only really works
# cause those schemas are identical.
# Also note these PG schemas talk about PG tickets and CM policies.
        signed_cred.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
        # FIXME: See v2 schema at www.geni.net/resources/credential/2/credential.xsd
        signed_cred.setAttribute("xsi:noNamespaceSchemaLocation", "http://www.planet-lab.org/resources/sfa/credential.xsd")
        signed_cred.setAttribute("xsi:schemaLocation", "http://www.planet-lab.org/resources/sfa/ext/policy/1 http://www.planet-lab.org/resources/sfa/ext/policy/1/policy.xsd")

# PG says for those last 2:
#        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")

        doc.appendChild(signed_cred)  
        
        # Fill in the <credential> bit        
        cred = doc.createElement("credential")
        cred.setAttribute("xml:id", self.get_refid())
        signed_cred.appendChild(cred)
        append_sub(doc, cred, "type", "privilege")
        append_sub(doc, cred, "serial", "8")
        append_sub(doc, cred, "owner_gid", self.gidCaller.save_to_string())
        append_sub(doc, cred, "owner_urn", self.gidCaller.get_urn())
        append_sub(doc, cred, "target_gid", self.gidObject.save_to_string())
        append_sub(doc, cred, "target_urn", self.gidObject.get_urn())
        append_sub(doc, cred, "uuid", "")
        if not self.expiration:
            self.set_expiration(datetime.datetime.utcnow() + datetime.timedelta(seconds=DEFAULT_CREDENTIAL_LIFETIME))
        self.expiration = self.expiration.replace(microsecond=0)
        if self.expiration.tzinfo is not None and self.expiration.tzinfo.utcoffset(self.expiration) is not None:
            # TZ aware. Make sure it is UTC
            self.expiration = self.expiration.astimezone(tz.tzutc())
        append_sub(doc, cred, "expires", self.expiration.strftime('%Y-%m-%dT%H:%M:%SZ')) # RFC3339
        privileges = doc.createElement("privileges")
        cred.appendChild(privileges)

        if self.privileges:
            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:\n - 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)
                        #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("utf-8")


    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

    ##
    # Sign the XML file created by encode()
    #
    # WARNING:
    # In general, a signed credential obtained externally should
    # not be changed else the signature is no longer valid.  So, once
    # you have loaded an existing signed credential, do not call encode() or sign() on it.

    def sign(self):
        if not self.issuer_privkey:
            return
        if not self.issuer_gid:
            return
        doc = parseString(self.get_xml())
        sigs = doc.getElementsByTagName("signatures")[0]

        # Create the signature template to be signed
        signature = Signature()
        signature.set_refid(self.get_refid())
        sdoc = parseString(signature.get_xml())        
        sig_ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
        sigs.appendChild(sig_ele)

        self.xml = doc.toxml("utf-8")


        # Split the issuer GID into multiple certificates if it's a chain
        chain = GID(filename=self.issuer_gid)
        gid_files = []
        while chain:
            gid_files.append(chain.save_to_random_tmp_file(False))
            if chain.get_parent():
                chain = chain.get_parent()
            else:
                chain = None


        # Call out to xmlsec1 to sign it
        ref = 'Sig_%s' % self.get_refid()
        filename = self.save_to_random_tmp_file()
        print "**********************************",'%s --sign --node-id "%s" --privkey-pem %s,%s %s' % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)
        command='%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
            % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)
#        print 'command',command
        signed = os.popen(command).read()
        print "*************************************",signed
        os.remove(filename)

        for gid_file in gid_files:
            os.remove(gid_file)

        self.xml = signed

        # This is no longer a legacy credential
        if self.legacy:
            self.legacy = None

        # Update signatures
        self.decode()       


    ##
    # 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:
            creds = signed_cred[0].getElementsByTagName("credential")
            signatures = signed_cred[0].getElementsByTagName("signatures")
            if len(signatures) > 0:
                sigs = signatures[0].getElementsByTagName("Signature")
        else:
            creds = doc.getElementsByTagName("credential")
        
        if creds is None or len(creds) == 0:
            # malformed cred file
            raise CredentialNotVerifiable("Malformed XML: No credential tag found")

        # Just take the first cred if there are more than one
        cred = creds[0]

        self.set_refid(cred.getAttribute("xml:id"))
        self.set_expiration(utcparse(getTextNode(cred, "expires")))

#        import traceback
#        stack = traceback.extract_stack()

        og = getTextNode(cred, "owner_gid")
        # ABAC creds will have this be None and use this method
#        if og is None:
#            found = False
#            for frame in stack:
#                if 'super(ABACCredential, self).decode()' in frame:
#                    found = True
#                    break
#            if not found:
#                raise CredentialNotVerifiable("Malformed XML: No owner_gid found")
        self.gidCaller = GID(string=og)
        tg = getTextNode(cred, "target_gid")
#        if tg is None:
#            found = False
#            for frame in stack:
#                if 'super(ABACCredential, self).decode()' in frame:
#                    found = True
#                    break
#            if not found:
#                raise CredentialNotVerifiable("Malformed XML: No target_gid found")
        self.gidObject = GID(string=tg)

        # Process privileges
        rlist = Rights()
        priv_nodes = cred.getElementsByTagName("privileges")
        if len(priv_nodes) > 0:
            privs = priv_nodes[0]
            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
                    # Each inherits the delegatability from the * above
                    _ , type = urn_to_hrn(self.gidObject.get_urn())
                    rl = determine_rights(type, self.gidObject.get_urn())
                    for r in rl.rights:
                        r.delegate = deleg
                        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("utf-8")
            if parent_xml is None or parent_xml.strip() == "":
                raise CredentialNotVerifiable("Malformed XML: Had parent tag but it is empty")
            self.parent = Credential(string=parent_xml)
            self.updateRefID()

        # Assign the signatures to the credentials
        for sig in sigs:
            Sig = Signature(string=sig.toxml("utf-8"))

            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.
    #
    #   trusted_certs_required: Should usually be true. Set False means an
    #                 empty list of trusted_certs would still let this method pass.
    #                 It just skips xmlsec1 verification et al. Only used by some utils
    #    
    # 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
    #    . Including verifying GID chains, and includ the issuer
    # . 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=None, schema=None, trusted_certs_required=True):
        if not self.xml:
            print "\n\n\n\n\n\n\n\n\n\n\n\n\n----------------------CRED\n\n\n\n\n\n\n\n\n\n\n\n\n"
            print "not xml"
            self.decode()

        # validate against RelaxNG schema
        if HAVELXML and 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: %s (line %s)" % (self.get_summary_tostring(), error.message, error.line)
                    raise CredentialNotVerifiable(message)

        if trusted_certs_required and trusted_certs is None:
            trusted_certs = []

#        trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
        trusted_cert_objects = []
        ok_trusted_certs = []
        # If caller explicitly passed in None that means skip cert chain validation.
        # Strange and not typical
        if trusted_certs is not None:
            for f in trusted_certs:
                try:
                    # Failures here include unreadable files
                    # or non PEM files
                    trusted_cert_objects.append(GID(filename=f))
                    ok_trusted_certs.append(f)
                except Exception, exc:
                    pass
            trusted_certs = ok_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_expiration() < datetime.datetime.utcnow():
            raise CredentialNotVerifiable("Credential %s expired at %s" % (self.get_summary_tostring(), self.expiration.isoformat()))

        # Verify the signatures
        filename = self.save_to_random_tmp_file()
        if trusted_certs is not None:
            cert_args = " ".join(['--trusted-pem %s' % x for x in trusted_certs])

        # If caller explicitly passed in None that means skip cert chain validation.
        # - Strange and not typical
        if trusted_certs is not None:
            # 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:
            # If caller explicitly passed in None that means skip xmlsec1 validation.
            # Strange and not typical
            if trusted_certs is None:
                break

            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"):
                # xmlsec errors have a msg= which is the interesting bit.
                mstart = verified.find("msg=")
                msg = ""
                if mstart > -1 and len(verified) > 4:
                    mstart = mstart + 4
                    mend = verified.find('\\', mstart)
                    msg = verified[mstart:mend]
                raise CredentialNotVerifiable("xmlsec1 error verifying cred %s using Signature ID %s: %s %s" % (self.get_summary_tostring(), ref, msg, verified.strip()))
        os.remove(filename)

        # Verify the parents (delegation)
        if self.parent:
            self.verify_parent(self.parent)

        # Make sure the issuer is the target's authority, and is
        # itself a valid GID
        self.verify_issuer(trusted_cert_objects)
        return True
Beispiel #7
0
class Signature(object):
   
    def __init__(self, string=None):
        self.refid = None
        self.issuer_gid = None
        self.xml = None
        if string:
            self.xml = string
            self.decode()


    def get_refid(self):
        if not self.refid:
            self.decode()
        return self.refid

    def get_xml(self):
        if not self.xml:
            self.encode()
        return self.xml

    def set_refid(self, id):
        self.refid = id

    def get_issuer_gid(self):
        if not self.gid:
            self.decode()
        return self.gid        

    def set_issuer_gid(self, gid):
        self.gid = gid

    def decode(self):
        try:
            doc = parseString(self.xml)
        except ExpatError,e:
            raise
        sig = doc.getElementsByTagName("Signature")[0]
        ref_id = sig.getAttribute("xml:id").strip().strip("Sig_")
        # The xml:id tag is optional, and could be in a 
        # Reference xml:id or Reference UID sub element instead
        if not ref_id or ref_id == '':
            reference = sig.getElementsByTagName('Reference')[0]
            ref_id = reference.getAttribute('xml:id').strip().strip('Sig_')
            if not ref_id or ref_id == '':
                ref_id = reference.getAttribute('URI').strip().strip('#')
        self.set_refid(ref_id)
        keyinfos = sig.getElementsByTagName("X509Data")
        gids = None
        for keyinfo in keyinfos:
            certs = keyinfo.getElementsByTagName("X509Certificate")
            for cert in certs:
                if len(cert.childNodes) > 0:
                    szgid = cert.childNodes[0].nodeValue
                    szgid = szgid.strip()
                    szgid = "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----" % szgid
                    if gids is None:
                        gids = szgid
                    else:
                        gids += "\n" + szgid
        if gids is None:
            raise CredentialNotVerifiable("Malformed XML: No certificate found in signature")
        self.set_issuer_gid(GID(string=gids))
Beispiel #8
0
                      help="filename of private key of signing user")
    parser.add_option('--trusted_roots_directory',
                      help='Directory of trusted root certs')
    parser.add_option('--create',
                      help="name of file of ABAC speaksfor cred to create")
    parser.add_option(
        '--useObject',
        action='store_true',
        default=False,
        help=
        'Use the ABACCredential object to create the credential (default False)'
    )

    options, args = parser.parse_args(sys.argv)

    tool_gid = GID(filename=options.tool_cert_file)

    if options.create:
        if options.user_cert_file and options.user_key_file \
            and options.ma_cert_file:
            user_gid = GID(filename=options.user_cert_file)
            ma_gid = GID(filename=options.ma_cert_file)
            if options.useObject:
                create_sign_abaccred(tool_gid, user_gid, ma_gid, \
                                         options.user_key_file,  \
                                         options.create)
            else:
                create_speaks_for(tool_gid, user_gid, ma_gid, \
                                         options.user_key_file,  \
                                         options.create)
        else:
Beispiel #9
0
                        uuidO = uuid.UUID(int=int(uuidarg))
                    except Exception, e:
                        try:
                            uuidO = uuid.UUID(fields=uuidarg)
                        except:
                            try:
                                uuidO = uuid.UUID(bytes=uuidarg)
                            except:
                                try:
                                    uuidO = uuid.UUID(bytes_le=uuidarg)
                                except:
                                    pass
        if uuidO is not None:
            uuidI = uuidO.int

    newgid = GID(create=True, subject=subject, uuid=uuidI, urn=urn, lifeDays=lifeDays)
    if email:
        newgid.set_email(email)
    
    if public_key is None:
        # create a new key pair
        keys = Keypair(create=True)
    else:
        # use the specified public key file
        keys = Keypair()
        keys.load_pubkey_from_file(public_key)
    newgid.set_pubkey(keys)
    newgid.set_is_ca(ca)

    if issuer_key and issuer_cert:
        # the given issuer will issue this cert
    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:
            creds = signed_cred[0].getElementsByTagName("credential")
            signatures = signed_cred[0].getElementsByTagName("signatures")
            if len(signatures) > 0:
                sigs = signatures[0].getElementsByTagName("Signature")
        else:
            creds = doc.getElementsByTagName("credential")
        
        if creds is None or len(creds) == 0:
            # malformed cred file
            raise CredentialNotVerifiable("Malformed XML: No credential tag found")

        # Just take the first cred if there are more than one
        cred = creds[0]

        self.set_refid(cred.getAttribute("xml:id"))
        self.set_expiration(utcparse(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 = Rights()
        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
                # Each inherits the delegatability from the * above
                _ , type = urn_to_hrn(self.gidObject.get_urn())
                rl = determine_rights(type, self.gidObject.get_urn())
                for r in rl.rights:
                    r.delegate = deleg
                    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)
Beispiel #11
0
                        try:
                            uuidO = uuid.UUID(fields=uuidarg)
                        except:
                            try:
                                uuidO = uuid.UUID(bytes=uuidarg)
                            except:
                                try:
                                    uuidO = uuid.UUID(bytes_le=uuidarg)
                                except:
                                    pass
        if uuidO is not None:
            uuidI = uuidO.int

    newgid = GID(create=True,
                 subject=subject,
                 uuid=uuidI,
                 urn=urn,
                 lifeDays=lifeDays)
    if email:
        newgid.set_email(email)

    if public_key is None:
        # create a new key pair
        keys = Keypair(create=True)
    else:
        # use the specified public key file
        keys = Keypair()
        keys.load_pubkey_from_file(public_key)
    newgid.set_pubkey(keys)
    newgid.set_is_ca(ca)