X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Ftrust%2Fspeaksfor_util.py;h=20819c9055dad5d837499a69b28b6537ab7db2b2;hb=a0ef6e7c91c3c8fa376943d28fec8c5c204a78cd;hp=ad2e97f5190d9727ac40d4793ca5b4c27b76a750;hpb=1e3c0e94e052ec15bca87bf65eb7ffb0061c6497;p=sfa.git diff --git a/sfa/trust/speaksfor_util.py b/sfa/trust/speaksfor_util.py index ad2e97f5..20819c90 100644 --- a/sfa/trust/speaksfor_util.py +++ b/sfa/trust/speaksfor_util.py @@ -21,6 +21,8 @@ # IN THE WORK. #---------------------------------------------------------------------- +from __future__ import print_function + import datetime from dateutil import parser as du_parser, tz as du_tz import optparse @@ -31,11 +33,14 @@ import tempfile from xml.dom.minidom import * from StringIO import StringIO +from sfa.util.sfatime import SFATIME_FORMAT + from sfa.trust.certificate import Certificate from sfa.trust.credential import Credential, signature_template, HAVELXML from sfa.trust.abac_credential import ABACCredential, ABACElement from sfa.trust.credential_factory import CredentialFactory from sfa.trust.gid import GID +from sfa.util.sfalogging import logger # Routine to validate that a speaks-for credential # says what it claims to say: @@ -129,26 +134,26 @@ def verify_speaks_for(cred, tool_gid, speaking_for_urn, # Credential has not expired if cred.expiration and cred.expiration < datetime.datetime.utcnow(): - return False, None, "ABAC Credential expired at %s (%s)" % (cred.expiration.isoformat(), cred.get_summary_tostring()) + return False, None, "ABAC Credential expired at %s (%s)" % (cred.expiration.strftime(SFATIME_FORMAT), cred.pretty_cred()) # Must be ABAC if cred.get_cred_type() != ABACCredential.ABAC_CREDENTIAL_TYPE: return False, None, "Credential not of type ABAC but %s" % cred.get_cred_type if cred.signature is None or cred.signature.gid is None: - return False, None, "Credential malformed: missing signature or signer cert. Cred: %s" % cred.get_summary_tostring() + return False, None, "Credential malformed: missing signature or signer cert. Cred: %s" % cred.pretty_cred() user_gid = cred.signature.gid user_urn = user_gid.get_urn() # URN of signer from cert must match URN of 'speaking-for' argument if user_urn != speaking_for_urn: return False, None, "User URN from cred doesn't match speaking_for URN: %s != %s (cred %s)" % \ - (user_urn, speaking_for_urn, cred.get_summary_tostring()) + (user_urn, speaking_for_urn, cred.pretty_cred()) tails = cred.get_tails() if len(tails) != 1: return False, None, "Invalid ABAC-SF credential: Need exactly 1 tail element, got %d (%s)" % \ - (len(tails), cred.get_summary_tostring()) + (len(tails), cred.pretty_cred()) user_keyid = get_cert_keyid(user_gid) tool_keyid = get_cert_keyid(tool_gid) @@ -165,7 +170,10 @@ def verify_speaks_for(cred, tool_gid, speaking_for_urn, for x in trusted_roots: cert_args += ['--trusted-pem', x.filename] # FIXME: Why do we not need to specify the --node-id option as credential.py does? - xmlsec1_args = [cred.xmlsec_path, '--verify'] + cert_args + [ cred_file] + xmlsec1 = cred.get_xmlsec1_path() + if not xmlsec1: + raise Exception("Could not locate required 'xmlsec1' program") + xmlsec1_args = [xmlsec1, '--verify'] + cert_args + [ cred_file] output = run_subprocess(xmlsec1_args, stdout=None, stderr=subprocess.PIPE) os.unlink(cred_file) if output != 0: @@ -186,7 +194,7 @@ def verify_speaks_for(cred, tool_gid, speaking_for_urn, if user_keyid != principal_keyid or \ tool_keyid != subject_keyid or \ role != ('speaks_for_%s' % user_keyid): - return False, None, "ABAC statement doesn't assert U.speaks_for(U)<-T (%s)" % cred.get_summary_tostring() + return False, None, "ABAC statement doesn't assert U.speaks_for(U)<-T (%s)" % cred.pretty_cred() # If schema provided, validate against schema if HAVELXML and schema and os.path.exists(schema): @@ -196,21 +204,21 @@ def verify_speaks_for(cred, tool_gid, speaking_for_urn, xmlschema = etree.XMLSchema(schema_doc) if not xmlschema.validate(tree): error = xmlschema.error_log.last_error - message = "%s: %s (line %s)" % (cred.get_summary_tostring(), error.message, error.line) + message = "%s: %s (line %s)" % (cred.pretty_cred(), error.message, error.line) return False, None, ("XML Credential schema invalid: %s" % message) if trusted_roots: # User certificate must validate against trusted roots try: user_gid.verify_chain(trusted_roots) - except Exception, e: + except Exception as e: return False, None, \ "Cred signer (user) cert not trusted: %s" % e # Tool certificate must validate against trusted roots try: tool_gid.verify_chain(trusted_roots) - except Exception, e: + except Exception as e: return False, None, \ "Tool cert not trusted: %s" % e @@ -229,10 +237,9 @@ def verify_speaks_for(cred, tool_gid, speaking_for_urn, # trusted_roots is a list of Certificate objects from the system # trusted_root directory # Optionally, provide an XML schema against which to validate the credential -def determine_speaks_for(logger, credentials, caller_gid, options, - trusted_roots, schema=None): - if options and 'geni_speaking_for' in options: - speaking_for_urn = options['geni_speaking_for'].strip() +def determine_speaks_for(logger, credentials, caller_gid, speaking_for_xrn, trusted_roots, schema=None): + if speaking_for_xrn: + speaking_for_urn = Xrn (speaking_for_xrn.strip()).get_urn() for cred in credentials: # Skip things that aren't ABAC credentials if type(cred) == dict: @@ -251,27 +258,24 @@ def determine_speaks_for(logger, credentials, caller_gid, options, if not isinstance(cred_value, ABACCredential): cred = CredentialFactory.createCred(cred_value) -# print "Got a cred to check speaksfor for: %s" % cred.get_summary_tostring() +# print("Got a cred to check speaksfor for: %s" % cred.pretty_cred()) # #cred.dump(True, True) -# print "Caller: %s" % caller_gid.dump_string(2, True) +# print("Caller: %s" % caller_gid.dump_string(2, True)) # See if this is a valid speaks_for is_valid_speaks_for, user_gid, msg = \ verify_speaks_for(cred, - caller_gid, speaking_for_urn, \ - trusted_roots, schema, logger=logger) + caller_gid, speaking_for_urn, + trusted_roots, schema, logger=logger) logger.info(msg) if is_valid_speaks_for: return user_gid # speaks-for else: - if logger: - logger.info("Got speaks-for option but not a valid speaks_for with this credential: %s" % msg) - else: - print "Got a speaks-for option but not a valid speaks_for with this credential: " + msg + logger.info("Got speaks-for option but not a valid speaks_for with this credential: %s" % msg) return caller_gid # Not speaks-for # Create an ABAC Speaks For credential using the ABACCredential object and it's encode&sign methods def create_sign_abaccred(tool_gid, user_gid, ma_gid, user_key_file, cred_filename, dur_days=365): - print "Creating ABAC SpeaksFor using ABACCredential...\n" + logger.info("Creating ABAC SpeaksFor using ABACCredential...\n") # Write out the user cert from tempfile import mkstemp ma_str = ma_gid.save_to_string() @@ -302,13 +306,12 @@ def create_sign_abaccred(tool_gid, user_gid, ma_gid, user_key_file, cred_filenam cred.sign() # Save it cred.save_to_file(cred_filename) - print "Created ABAC credential: '%s' in file %s" % \ - (cred.get_summary_tostring(), cred_filename) + logger.info("Created ABAC credential: '%s' in file %s" % + (cred.pretty_cred(), cred_filename)) -# FIXME: Assumes xmlsec1 is on path # FIXME: Assumes signer is itself signed by an 'ma_gid' that can be trusted -def create_speaks_for(tool_gid, user_gid, ma_gid, \ - user_key_file, cred_filename, dur_days=365): +def create_speaks_for(tool_gid, user_gid, ma_gid, + user_key_file, cred_filename, dur_days=365): tool_urn = tool_gid.get_urn() user_urn = user_gid.get_urn() @@ -349,15 +352,15 @@ def create_speaks_for(tool_gid, user_gid, ma_gid, \ credential_duration = datetime.timedelta(days=dur_days) - expiration = datetime.datetime.now(du_tz.tzutc()) + credential_duration - expiration_str = expiration.strftime('%Y-%m-%dT%H:%M:%SZ') # FIXME: libabac can't handle .isoformat() + expiration = datetime.datetime.utcnow() + credential_duration + expiration_str = expiration.strftime(SFATIME_FORMAT) version = "1.1" user_keyid = get_cert_keyid(user_gid) tool_keyid = get_cert_keyid(tool_gid) - unsigned_cred = template % (reference, expiration_str, version, \ - user_keyid, user_urn, user_keyid, tool_keyid, tool_urn, \ - reference, reference) + unsigned_cred = template % (reference, expiration_str, version, + user_keyid, user_urn, user_keyid, tool_keyid, tool_urn, + reference, reference) unsigned_cred_filename = write_to_tempfile(unsigned_cred) # Now sign the file with xmlsec1 @@ -365,17 +368,19 @@ def create_speaks_for(tool_gid, user_gid, ma_gid, \ # --output signed.xml tosign.xml pems = "%s,%s,%s" % (user_key_file, user_gid.get_filename(), ma_gid.get_filename()) - # FIXME: assumes xmlsec1 is on path - cmd = ['xmlsec1', '--sign', '--privkey-pem', pems, + xmlsec1 = Credential.get_xmlsec1_path() + if not xmlsec1: + raise Exception("Could not locate required 'xmlsec1' program") + cmd = [ xmlsec1, '--sign', '--privkey-pem', pems, '--output', cred_filename, unsigned_cred_filename] -# print " ".join(cmd) +# print(" ".join(cmd)) sign_proc_output = run_subprocess(cmd, stdout=subprocess.PIPE, stderr=None) if sign_proc_output == None: - print "OUTPUT = %s" % sign_proc_output + logger.info("xmlsec1 returns empty output") else: - print "Created ABAC credential: '%s speaks_for %s' in file %s" % \ - (tool_urn, user_urn, cred_filename) + logger.info("Created ABAC credential: '%s speaks_for %s' in file %s" % + (tool_urn, user_urn, cred_filename)) os.unlink(unsigned_cred_filename) @@ -412,17 +417,17 @@ if __name__ == "__main__": 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) + 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) + create_speaks_for(tool_gid, user_gid, ma_gid, + options.user_key_file, + options.create) else: - print "Usage: --create cred_file " + \ - "--user_cert_file user_cert_file" + \ - " --user_key_file user_key_file --ma_cert_file ma_cert_file" + print("Usage: --create cred_file " + + "--user_cert_file user_cert_file" + + " --user_key_file user_key_file --ma_cert_file ma_cert_file") sys.exit() user_urn = options.user_urn @@ -433,18 +438,18 @@ if __name__ == "__main__": trusted_roots_directory = options.trusted_roots_directory trusted_roots = \ - [Certificate(filename=os.path.join(trusted_roots_directory, file)) \ - for file in os.listdir(trusted_roots_directory) \ + [Certificate(filename=os.path.join(trusted_roots_directory, file)) + for file in os.listdir(trusted_roots_directory) if file.endswith('.pem') and file != 'CATedCACerts.pem'] cred = open(options.cred_file).read() creds = [{'geni_type' : ABACCredential.ABAC_CREDENTIAL_TYPE, 'geni_value' : cred, 'geni_version' : '1'}] - gid = determine_speaks_for(None, creds, tool_gid, \ - {'geni_speaking_for' : user_urn}, \ - trusted_roots) + gid = determine_speaks_for(None, creds, tool_gid, + {'geni_speaking_for' : user_urn}, + trusted_roots) - print 'SPEAKS_FOR = %s' % (gid != tool_gid) - print "CERT URN = %s" % gid.get_urn() + print('SPEAKS_FOR = %s' % (gid != tool_gid)) + print("CERT URN = %s" % gid.get_urn())