######## Start up the server
# not too nice, but.. when co-located with myplc we'll let it start/stop postgresql
- if [ ! postgresql_check ] ; then
+ postgresql_check || {
service postgresql start >& /dev/null
MESSAGE=$"Starting PostgreSQL server"
echo -n "$MESSAGE"
[ "$ERRORS" == 0 ] && success "$MESSAGE" || failure "$MESSAGE" ; echo
# best-effort to make sure we turn it back off when running stop
touch $POSTGRESQL_STARTED
- fi
+ }
postgresql_check
check
%define name sfa
%define version 3.1
-%define taglevel 18
+%define taglevel 20
%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
%global python_sitearch %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
#[ "$1" -ge "1" ] && service sfa-cm restart || :
%changelog
+* Thu Dec 17 2015 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-3.1-20
+- minor fixes for migrating on fedora23
+
+* Tue Dec 08 2015 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-3.1-19
+- imported changes from GENI as reported - Aaron Helsinger
+- minimal changes so that parts can be imported from nepi/py3
+- iotlab driver : fix ASAP jobs with state != Waiting, Running - Frederic
+- sfi client more accurately advertises rspec version - Loic
+- + bugfix in initscript
+
* Mon Jun 08 2015 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-3.1-18
- incorporated Frederic Saint Marcel's addition of ASAP management tag
# starting with 2.7.9 we need to turn off server verification
import ssl
-ssl_needs_unverified_context = hasattr(ssl, '_create_unverified_context')
+try: turn_off_server_verify = { 'context' : ssl._create_unverified_context() }
+except: turn_off_server_verify = {}
import xmlrpclib
import getpass
# return self._proxy
url=self.url()
self.logger.debug("Connecting manifold url %s"%url)
- if not ssl_needs_unverified_context:
- proxy = xmlrpclib.ServerProxy(url, allow_none = True)
- else:
- proxy = xmlrpclib.ServerProxy(url, allow_none = True,
- context=ssl._create_unverified_context())
+ proxy = xmlrpclib.ServerProxy(url, allow_none = True,
+ **turn_off_server_verify)
+
return proxy
# does the job for one credential
# starting with 2.7.9 we need to turn off server verification
import ssl
-ssl_needs_unverified_context = hasattr(ssl, '_create_unverified_context')
+try: turn_off_server_verify = { 'context' : ssl._create_unverified_context() }
+except: turn_off_server_verify = {}
import xmlrpclib
from httplib import HTTPS, HTTPSConnection
# create a HTTPS connection object from a host descriptor
# host may be a string, or a (host, x509-dict) tuple
host, extra_headers, x509 = self.get_host_info(host)
- if not ssl_needs_unverified_context:
- conn = HTTPSConnection(host, None, key_file = self.key_file,
- cert_file = self.cert_file)
- else:
- conn = HTTPSConnection(host, None, key_file = self.key_file,
- cert_file = self.cert_file,
- context = ssl._create_unverified_context())
+ conn = HTTPSConnection(host, None, key_file = self.key_file,
+ cert_file = self.cert_file,
+ **turn_off_server_verify)
# Some logic to deal with timeouts. It appears that some (or all) versions
# of python don't set the timeout after the socket is created. We'll do it
# remember url for GetVersion
# xxx not sure this is still needed as SfaServerProxy has this too
self.url=url
- if not ssl_needs_unverified_context:
- xmlrpclib.ServerProxy.__init__(self, url, transport, allow_none=allow_none,
- verbose=verbose)
- else:
- xmlrpclib.ServerProxy.__init__(self, url, transport, allow_none=allow_none,
- verbose=verbose,
- context=ssl._create_unverified_context())
+ xmlrpclib.ServerProxy.__init__(self, url, transport, allow_none=allow_none,
+ verbose=verbose,
+ **turn_off_server_verify)
def __getattr__(self, attr):
logger.debug ("xml-rpc %s method:%s" % (self.url, attr))
# this module is also used in sfascan
#
+from __future__ import print_function
+
import sys
sys.path.append('.')
else:
result = rspec
- print result
+ print(result)
return
def display_list(results):
for result in results:
- print result
+ print(result)
def display_records(recordList, dump=False):
''' Print all fields in the record'''
record.dump(sort=True)
else:
info = record.getdict()
- print "{} ({})".format(info['hrn'], info['type'])
+ print("{} ({})".format(info['hrn'], info['type']))
return
def credential_printable (cred):
credential = Credential(cred=cred)
- result=""
+ result = ""
result += credential.pretty_cred()
result += "\n"
rights = credential.get_privileges()
return result
def show_credentials (cred_s):
- if not isinstance (cred_s,list): cred_s = [cred_s]
+ if not isinstance (cred_s, list): cred_s = [cred_s]
for cred in cred_s:
- print "Using Credential {}".format(credential_printable(cred))
+ print("Using Credential {}".format(credential_printable(cred)))
########## save methods
else:
with open(filename, w) as fileobj:
_save_raw_to_file(var, fileobj, format, banner)
- print "(Over)wrote {}".format(filename)
+ print("(Over)wrote {}".format(filename))
def _save_raw_to_file(var, f, format, banner):
if format == "text":
f.write(json.dumps(var)) # python 2.6
else:
# this should never happen
- print "unknown output format", format
+ print("unknown output format", format)
###
def save_rspec_to_file(rspec, filename):
filename = filename + ".rspec"
with open(filename, 'w') as f:
f.write("{}".format(rspec))
- print "(Over)wrote {}".format(filename)
+ print("(Over)wrote {}".format(filename))
def save_record_to_file(filename, record_dict):
record = Record(dict=record_dict)
xml = record.save_as_xml()
- with codecs.open(filename, encoding='utf-8',mode="w") as f:
+ with codecs.open(filename, encoding='utf-8', mode="w") as f:
f.write(xml)
- print "(Over)wrote {}".format(filename)
+ print("(Over)wrote {}".format(filename))
def save_records_to_file(filename, record_dicts, format="xml"):
if format == "xml":
record_obj = Record(dict=record_dict)
f.write('<record hrn="' + record_obj.hrn + '" type="' + record_obj.type + '" />\n')
f.write("</recordlist>\n")
- print "(Over)wrote {}".format(filename)
+ print("(Over)wrote {}".format(filename))
elif format == "hrnlist":
with open(filename, "w") as f:
for record_dict in record_dicts:
record_obj = Record(dict=record_dict)
f.write(record_obj.hrn + "\n")
- print "(Over)wrote {}".format(filename)
+ print("(Over)wrote {}".format(filename))
else:
# this should never happen
- print "unknown output format", format
+ print("unknown output format", format)
# minimally check a key argument
def check_ssh_key (key):
elif type.startswith('al'):
return 'all'
else:
- print 'unknown type {} - should start with one of au|us|sl|no|ag|al'.format(type)
+ print('unknown type {} - should start with one of au|us|sl|no|ag|al'.format(type))
return None
def load_record_from_opts(options):
except IOError:
pubkey = options.key
if not check_ssh_key (pubkey):
- raise SfaInvalidArgument(name='key',msg="Could not find file, or wrong key format")
+ raise SfaInvalidArgument(name='key', msg="Could not find file, or wrong key format")
record_dict['reg-keys'] = [pubkey]
if hasattr(options, 'slices') and options.slices:
record_dict['slices'] = options.slices
commands_list=[]
commands_dict={}
-def declare_command (args_string, example,aliases=None):
+def declare_command (args_string, example, aliases=None):
def wrap(m):
- name=getattr(m,'__name__')
- doc=getattr(m,'__doc__',"-- missing doc --")
+ name=getattr(m, '__name__')
+ doc=getattr(m, '__doc__', "-- missing doc --")
doc=doc.strip(" \t\n")
commands_list.append(name)
# last item is 'canonical' name, so we can know which commands are aliases
- command_tuple=(doc, args_string, example,name)
+ command_tuple=(doc, args_string, example, name)
commands_dict[name]=command_tuple
if aliases is not None:
for alias in aliases:
def remove_none_fields (record):
- none_fields=[ k for (k,v) in record.items() if v is None ]
+ none_fields=[ k for (k, v) in record.items() if v is None ]
for k in none_fields: del record[k]
##########
class DummyOptions:
pass
- def __init__ (self,options=None):
+ def __init__ (self, options=None):
if options is None: options=Sfi.DummyOptions()
for opt in Sfi.required_options:
- if not hasattr(options,opt): setattr(options,opt,None)
- if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir()
+ if not hasattr(options, opt):
+ setattr(options, opt, None)
+ if not hasattr(options, 'sfi_dir'):
+ options.sfi_dir = Sfi.default_sfi_dir()
self.options = options
self.user = None
self.authority = None
### various auxiliary material that we keep at hand
self.command=None
# need to call this other than just 'config' as we have a command/method with that name
- self.config_instance=None
- self.config_file=None
- self.client_bootstrap=None
+ self.config_instance = None
+ self.config_file = None
+ self.client_bootstrap = None
### suitable if no reasonable command has been provided
def print_commands_help (self, options):
- verbose=getattr(options,'verbose')
- format3="%10s %-35s %s"
- format3offset=47
- line=80*'-'
+ verbose = getattr(options, 'verbose')
+ format3 = "%10s %-35s %s"
+ format3offset = 47
+ line = 80*'-'
if not verbose:
- print format3%("command", "cmd_args", "description")
- print line
+ print(format3%("command", "cmd_args", "description"))
+ print(line)
else:
- print line
+ print(line)
self.create_parser_global().print_help()
# preserve order from the code
for command in commands_list:
try:
(doc, args_string, example, canonical) = commands_dict[command]
except:
- print "Cannot find info on command %s - skipped"%command
+ print("Cannot find info on command %s - skipped"%command)
continue
if verbose:
- print line
+ print(line)
if command==canonical:
doc = doc.replace("\n", "\n" + format3offset * ' ')
- print format3 % (command,args_string,doc)
+ print(format3 % (command, args_string, doc))
if verbose:
self.create_parser_command(command).print_help()
else:
- print format3 % (command,"<<alias for %s>>"%canonical,"")
+ print(format3 % (command, "<<alias for %s>>"%canonical, ""))
### now if a known command was found we can be more verbose on that one
def print_help (self):
- print "==================== Generic sfi usage"
+ print("==================== Generic sfi usage")
self.sfi_parser.print_help()
(doc, _, example, canonical) = commands_dict[self.command]
if canonical != self.command:
- print "\n==================== NOTE: {} is an alias for genuine {}"\
- .format(self.command, canonical)
+ print("\n==================== NOTE: {} is an alias for genuine {}"
+ .format(self.command, canonical))
self.command = canonical
- print "\n==================== Purpose of {}".format(self.command)
- print doc
- print "\n==================== Specific usage for {}".format(self.command)
+ print("\n==================== Purpose of {}".format(self.command))
+ print(doc)
+ print("\n==================== Specific usage for {}".format(self.command))
self.command_parser.print_help()
if example:
- print "\n==================== {} example(s)".format(self.command)
- print example
+ print("\n==================== {} example(s)".format(self.command))
+ print(example)
def create_parser_global(self):
# Generate command line parser
sys.exit(2)
# retrieve args_string
- (_, args_string, __,canonical) = commands_dict[command]
+ (_, args_string, __, canonical) = commands_dict[command]
parser = OptionParser(add_help_option=False,
usage="sfi [sfi_options] {} [cmd_options] {}"\
(doc, args_string, example, canonical) = commands_dict[command]
method=getattr(self, canonical, None)
if not method:
- print "sfi: unknown command {}".format(command)
+ print("sfi: unknown command {}".format(command))
raise SystemExit("Unknown command {}".format(command))
for arg in command_args:
if 'help' in arg or arg == '-h':
self.print_commands_help(options)
sys.exit(1)
# second pass options parsing
- self.command=command
+ self.command = command
self.command_parser = self.create_parser_command(command)
(command_options, command_args) = self.command_parser.parse_args(args[1:])
if command_options.help:
####################
def read_config(self):
- config_file = os.path.join(self.options.sfi_dir,"sfi_config")
- shell_config_file = os.path.join(self.options.sfi_dir,"sfi_config.sh")
+ config_file = os.path.join(self.options.sfi_dir, "sfi_config")
+ shell_config_file = os.path.join(self.options.sfi_dir, "sfi_config.sh")
try:
if Config.is_ini(config_file):
config = Config (config_file)
except:
self.logger.critical("Failed to read configuration file {}".format(config_file))
self.logger.info("Make sure to remove the export clauses and to add quotes")
- if self.options.verbose==0:
+ if self.options.verbose == 0:
self.logger.info("Re-run with -v for more details")
else:
self.logger.log_exc("Could not read config file {}".format(config_file))
sys.exit(1)
- self.config_instance=config
+ self.config_instance = config
errors = 0
# Set SliceMgr URL
if (self.options.sm is not None):
self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in {}".format(config_file))
errors += 1
- self.config_file=config_file
+ self.config_file = config_file
if errors:
sys.exit(1)
caller_gidfile = self.my_gid()
# the gid of the user who will be delegated to
- delegee_gid = self.client_bootstrap.gid(hrn,type)
+ delegee_gid = self.client_bootstrap.gid(hrn, type)
delegee_hrn = delegee_gid.get_hrn()
dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile)
return dcred.save_to_string(save_parents=True)
# cache the result
if not hasattr (self, 'sliceapi_proxy'):
# if the command exposes the --component option, figure it's hostname and connect at CM_PORT
- if hasattr(self.command_options,'component') and self.command_options.component:
+ if hasattr(self.command_options, 'component') and self.command_options.component:
# resolve the hrn at the registry
node_hrn = self.command_options.component
records = self.registry().Resolve(node_hrn, self.my_credential_string)
self.logger.warning("No such component:{}".format(opts.component))
record = records[0]
cm_url = "http://{}:{}/".format(record['hostname'], CM_PORT)
- self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid)
+ self.sliceapi_proxy = SfaServerProxy(cm_url, self.private_key, self.my_gid)
else:
# otherwise use what was provided as --sliceapi, or SFI_SM in the config
if not self.sm_url.startswith('http://') or self.sm_url.startswith('https://'):
# check local cache first
cache = None
version = None
- cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
+ cache_file = os.path.join(self.options.sfi_dir, 'sfi_cache.dat')
cache_key = server.url + "-version"
try:
cache = Cache(cache_file)
if not version:
result = server.GetVersion()
- version= ReturnValue.get_value(result)
+ version = ReturnValue.get_value(result)
# cache version for 20 minutes
- cache.add(cache_key, version, ttl= 60*20)
+ cache.add(cache_key, version, ttl=60*20)
self.logger.info("Updating cache file {}".format(cache_file))
cache.save_to_file(cache_file)
# helper function to analyze raw output
# for main : return 0 if everything is fine, something else otherwise (mostly 1 for now)
def success (self, raw):
- return_value=ReturnValue (raw)
- output=ReturnValue.get_output(return_value)
+ return_value = ReturnValue(raw)
+ output = ReturnValue.get_output(return_value)
# means everything is fine
if not output:
return 0
# something went wrong
- print 'ERROR:',output
+ print('ERROR:', output)
return 1
#==========================================================================
# Registry-related commands
#==========================================================================
- @declare_command("","")
+ @declare_command("", "")
def config (self, options, args):
"Display contents of current config"
- print "# From configuration file {}".format(self.config_file)
- flags=[ ('sfi', [ ('registry','reg_url'),
- ('auth','authority'),
- ('user','user'),
- ('sm','sm_url'),
- ]),
+ print("# From configuration file {}".format(self.config_file))
+ flags = [ ('sfi', [ ('registry', 'reg_url'),
+ ('auth', 'authority'),
+ ('user', 'user'),
+ ('sm', 'sm_url'),
+ ]),
]
if options.myslice:
flags.append ( ('myslice', ['backend', 'delegate', 'platform', 'username'] ) )
for (section, tuples) in flags:
- print "[{}]".format(section)
+ print("[{}]".format(section))
try:
- for (external_name, internal_name) in tuples:
- print "{:-20} = {}".format(external_name, getattr(self, internal_name))
+ for external_name, internal_name in tuples:
+ print("{:<20} = {}".format(external_name, getattr(self, internal_name)))
except:
- for name in tuples:
- varname = "{}_{}".format(section.upper(), name.upper())
- value = getattr(self.config_instance,varname)
- print "{:-20} = {}".format(name, value)
+ for external_name, internal_name in tuples:
+ varname = "{}_{}".format(section.upper(), external_name.upper())
+ value = getattr(self.config_instance, varname)
+ print("{:<20} = {}".format(external_name, value))
# xxx should analyze result
return 0
- @declare_command("","")
+ @declare_command("", "")
def version(self, options, args):
"""
display an SFA server version (GetVersion)
or version information about sfi itself
"""
if options.version_local:
- version=version_core()
+ version = version_core()
else:
if options.registry_interface:
- server=self.registry()
+ server = self.registry()
else:
server = self.sliceapi()
result = server.GetVersion()
# xxx should analyze result
return 0
- @declare_command("authority","")
+ @declare_command("authority", "")
def list(self, options, args):
"""
list entries in named authority registry (List)
"""
- if len(args)!= 1:
+ if len(args) != 1:
self.print_help()
sys.exit(1)
hrn = args[0]
try:
list = self.registry().List(hrn, self.my_credential_string, options)
except IndexError:
- raise Exception, "Not enough parameters for the 'list' command"
+ raise Exception("Not enough parameters for the 'list' command")
# filter on person, slice, site, node, etc.
# This really should be in the self.filter_records funct def comment...
# xxx should analyze result
return 0
- @declare_command("name","")
+ @declare_command("name", "")
def show(self, options, args):
"""
show details about named registry record (Resolve)
"""
- if len(args)!= 1:
+ if len(args) != 1:
self.print_help()
sys.exit(1)
hrn = args[0]
# explicitly require Resolve to run in details mode
- resolve_options={}
- if not options.no_details: resolve_options['details']=True
+ resolve_options = {}
+ if not options.no_details:
+ resolve_options['details'] = True
record_dicts = self.registry().Resolve(hrn, self.my_credential_string, resolve_options)
record_dicts = filter_records(options.type, record_dicts)
if not record_dicts:
# user has required to focus on some keys
if options.keys:
def project (record):
- projected={}
+ projected = {}
for key in options.keys:
- try: projected[key]=record[key]
+ try: projected[key] = record[key]
except: pass
return projected
record_dicts = [ project (record) for record in record_dicts ]
records = [ Record(dict=record_dict) for record_dict in record_dicts ]
for record in records:
if (options.format == "text"): record.dump(sort=True)
- else: print record.save_as_xml()
+ else: print(record.save_as_xml())
if options.file:
save_records_to_file(options.file, record_dicts, options.fileformat)
# xxx should analyze result
return 0
# this historically was named 'add', it is now 'register' with an alias for legacy
- @declare_command("[xml-filename]","",['add'])
+ @declare_command("[xml-filename]", "", ['add'])
def register(self, options, args):
"""create new record in registry (Register)
from command line options (recommended)
if len(args) > 1:
self.print_help()
sys.exit(1)
- if len(args)==1:
+ if len(args) == 1:
try:
record_filepath = args[0]
rec_file = self.get_record_file(record_filepath)
record_dict.update(load_record_from_file(rec_file).record_to_dict())
except:
- print "Cannot load record file {}".format(record_filepath)
+ print("Cannot load record file {}".format(record_filepath))
sys.exit(1)
if options:
record_dict.update(load_record_from_opts(options).record_to_dict())
# xxx should analyze result
return 0
- @declare_command("[xml-filename]","")
+ @declare_command("[xml-filename]", "")
def update(self, options, args):
"""update record into registry (Update)
from command line options (recommended)
elif record_dict['type'] in ['slice']:
try:
cred = self.slice_credential_string(record_dict['hrn'])
- except ServerException, e:
+ except ServerException as e:
# XXX smbaker -- once we have better error return codes, update this
# to do something better than a string compare
if "Permission error" in e.args[0]:
# xxx should analyze result
return 0
- @declare_command("hrn","")
+ @declare_command("hrn", "")
def remove(self, options, args):
"remove registry record by name (Remove)"
auth_cred = self.my_authority_credential_string()
- if len(args)!=1:
+ if len(args) != 1:
self.print_help()
sys.exit(1)
hrn = args[0]
# ==================================================================
# show rspec for named slice
- @declare_command("","",['discover'])
+ @declare_command("", "", ['discover'])
def resources(self, options, args):
"""
discover available resources (ListResources)
# just request the version the client wants
api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
else:
- api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'}
+ api_options['geni_rspec_version'] = {'type': options.rspec_version}
else:
api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3'}
+
list_resources = server.ListResources (creds, api_options)
value = ReturnValue.get_value(list_resources)
if self.options.raw:
display_rspec(value, options.format)
return self.success(list_resources)
- @declare_command("slice_hrn","")
+ @declare_command("slice_hrn", "")
def describe(self, options, args):
"""
shows currently allocated/provisioned resources
display_rspec(value['geni_rspec'], options.format)
return self.success (describe)
- @declare_command("slice_hrn [<sliver_urn>...]","")
+ @declare_command("slice_hrn [<sliver_urn>...]", "")
def delete(self, options, args):
"""
de-allocate and de-provision all or named slivers of the named slice (Delete)
if self.options.raw:
save_raw_to_file(delete, self.options.raw, self.options.rawformat, self.options.rawbanner)
else:
- print value
+ print(value)
return self.success (delete)
- @declare_command("slice_hrn rspec","")
+ @declare_command("slice_hrn rspec", "")
def allocate(self, options, args):
"""
allocate resources to the named slice (Allocate)
geni_users = []
slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string])
remove_none_fields(slice_records[0])
- if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']!=[]:
+ if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers'] != []:
slice_record = slice_records[0]
user_hrns = slice_record['reg-researchers']
user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
if options.file is not None:
save_rspec_to_file (value['geni_rspec'], options.file)
if (self.options.raw is None) and (options.file is None):
- print value
+ print(value)
return self.success(allocate)
- @declare_command("slice_hrn [<sliver_urn>...]","")
+ @declare_command("slice_hrn [<sliver_urn>...]", "")
def provision(self, options, args):
"""
provision all or named already allocated slivers of the named slice (Provision)
# }]
users = []
slice_records = self.registry().Resolve(slice_urn, [self.my_credential_string])
- if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers']!=[]:
+ if slice_records and 'reg-researchers' in slice_records[0] and slice_records[0]['reg-researchers'] != []:
slice_record = slice_records[0]
user_hrns = slice_record['reg-researchers']
user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
if options.file is not None:
save_rspec_to_file (value['geni_rspec'], options.file)
if (self.options.raw is None) and (options.file is None):
- print value
+ print(value)
return self.success(provision)
- @declare_command("slice_hrn","")
+ @declare_command("slice_hrn", "")
def status(self, options, args):
"""
retrieve the status of the slivers belonging to the named slice (Status)
# options and call_id when supported
api_options = {}
- api_options['call_id']=unique_call_id()
+ api_options['call_id'] = unique_call_id()
if options.show_credential:
show_credentials(creds)
- status = server.Status([slice_urn], creds, *self.ois(server,api_options))
+ status = server.Status([slice_urn], creds, *self.ois(server, api_options))
value = ReturnValue.get_value(status)
if self.options.raw:
save_raw_to_file(status, self.options.raw, self.options.rawformat, self.options.rawbanner)
else:
- print value
+ print(value)
return self.success (status)
- @declare_command("slice_hrn [<sliver_urn>...] action","")
+ @declare_command("slice_hrn [<sliver_urn>...] action", "")
def action(self, options, args):
"""
Perform the named operational action on all or named slivers of the named slice
if self.options.raw:
save_raw_to_file(perform_action, self.options.raw, self.options.rawformat, self.options.rawbanner)
else:
- print value
+ print(value)
return self.success (perform_action)
@declare_command("slice_hrn [<sliver_urn>...] time",
creds = [slice_cred]
# options and call_id when supported
api_options = {}
- api_options['call_id']=unique_call_id()
+ api_options['call_id'] = unique_call_id()
if options.alap:
- api_options['geni_extend_alap']=True
+ api_options['geni_extend_alap'] = True
if options.show_credential:
show_credentials(creds)
- renew = server.Renew(sliver_urns, creds, input_time, *self.ois(server,api_options))
+ renew = server.Renew(sliver_urns, creds, input_time, *self.ois(server, api_options))
value = ReturnValue.get_value(renew)
if self.options.raw:
save_raw_to_file(renew, self.options.raw, self.options.rawformat, self.options.rawbanner)
else:
- print value
+ print(value)
return self.success(renew)
- @declare_command("slice_hrn","")
+ @declare_command("slice_hrn", "")
def shutdown(self, options, args):
"""
shutdown named slice (Shutdown)
if self.options.raw:
save_raw_to_file(shutdown, self.options.raw, self.options.rawformat, self.options.rawbanner)
else:
- print value
+ print(value)
return self.success (shutdown)
- @declare_command("[name]","")
+ @declare_command("[name]", "")
def gid(self, options, args):
"""
Create a GID (CreateGid)
return 0
####################
- @declare_command("to_hrn","""$ sfi delegate -u -p -s ple.inria.heartbeat -s ple.inria.omftest ple.upmc.slicebrowser
+ @declare_command("to_hrn", """$ sfi delegate -u -p -s ple.inria.heartbeat -s ple.inria.omftest ple.upmc.slicebrowser
will locally create a set of delegated credentials for the benefit of ple.upmc.slicebrowser
the set of credentials in the scope for this call would be
original = self.slice_credential_string(slice_hrn)
tuples.append ( (message, original,) )
if options.delegate_pi:
- my_authority=self.authority
+ my_authority = self.authority
message = "{}.pi".format(my_authority)
original = self.my_authority_credential_string()
tuples.append ( (message, original,) )
original = self.authority_credential_string(auth_hrn)
tuples.append ( (message, original, ) )
# if nothing was specified at all at this point, let's assume -u
- if not tuples: options.delegate_user=True
+ if not tuples:
+ options.delegate_user = True
# this user cred
if options.delegate_user:
message = "{}.user".format(self.user)
tuples.append ( (message, original, ) )
# default type for beneficial is user unless -A
- if options.delegate_to_authority: to_type='authority'
- else: to_type='user'
+ to_type = 'authority' if options.delegate_to_authority else 'user'
# let's now handle all this
# it's all in the filenaming scheme
- for (message,original) in tuples:
+ for (message, original) in tuples:
delegated_string = self.client_bootstrap.delegate_credential_string(original, to_hrn, to_type)
delegated_credential = Credential (string=delegated_string)
filename = os.path.join(self.options.sfi_dir,
.format(message, to_hrn, filename))
####################
- @declare_command("","""$ less +/myslice sfi_config
+ @declare_command("", """$ less +/myslice sfi_config
[myslice]
backend = http://manifold.pl.sophia.inria.fr:7080
# the HRN that myslice uses, so that we are delegating to
self.client_bootstrap.my_pkcs12()
# (a) rain check for sufficient config in sfi_config
- myslice_dict={}
- myslice_keys=[ 'backend', 'delegate', 'platform', 'username']
+ myslice_dict = {}
+ myslice_keys = [ 'backend', 'delegate', 'platform', 'username']
for key in myslice_keys:
- value=None
+ value = None
# oct 2013 - I'm finding myself juggling with config files
# so a couple of command-line options can now override config
- if hasattr(options,key) and getattr(options,key) is not None:
- value=getattr(options,key)
+ if hasattr(options, key) and getattr(options, key) is not None:
+ value = getattr(options, key)
else:
- full_key="MYSLICE_" + key.upper()
- value=getattr(self.config_instance,full_key,None)
+ full_key = "MYSLICE_" + key.upper()
+ value = getattr(self.config_instance, full_key, None)
if value:
- myslice_dict[key]=value
+ myslice_dict[key] = value
else:
- print "Unsufficient config, missing key {} in [myslice] section of sfi_config"\
- .format(key)
+ print("Unsufficient config, missing key {} in [myslice] section of sfi_config"
+ .format(key))
if len(myslice_dict) != len(myslice_keys):
sys.exit(1)
# (b) figure whether we are PI for the authority where we belong
self.logger.info("Resolving our own id {}".format(self.user))
- my_records=self.registry().Resolve(self.user,self.my_credential_string)
+ my_records = self.registry().Resolve(self.user, self.my_credential_string)
if len(my_records) != 1:
- print "Cannot Resolve {} -- exiting".format(self.user)
+ print("Cannot Resolve {} -- exiting".format(self.user))
sys.exit(1)
my_record = my_records[0]
my_auths_all = my_record['reg-pi-authorities']
self.logger.debug("Restricted to user-provided auths {}".format(my_auths))
# (c) get the set of slices that we are in
- my_slices_all=my_record['reg-slices']
+ my_slices_all = my_record['reg-slices']
self.logger.info("Found {} slices that we are member of".format(len(my_slices_all)))
self.logger.debug("They are: {}".format(my_slices_all))
self.logger.debug("Restricted to user-provided slices: {}".format(my_slices))
# (d) make sure we have *valid* credentials for all these
- hrn_credentials=[]
+ hrn_credentials = []
hrn_credentials.append ( (self.user, 'user', self.my_credential_string,) )
for auth_hrn in my_auths:
hrn_credentials.append ( (auth_hrn, 'auth', self.authority_credential_string(auth_hrn),) )
# (e) check for the delegated version of these
# xxx todo add an option -a/-A? like for 'sfi delegate' for when we ever
# switch to myslice using an authority instead of a user
- delegatee_type='user'
- delegatee_hrn=myslice_dict['delegate']
+ delegatee_type = 'user'
+ delegatee_hrn = myslice_dict['delegate']
hrn_delegated_credentials = []
for (hrn, htype, credential) in hrn_credentials:
delegated_credential = self.client_bootstrap.delegate_credential_string (credential, delegatee_hrn, delegatee_type)
filename = os.path.join ( self.options.sfi_dir,
"{}.{}_for_{}.{}.cred"\
.format(hrn, htype, delegatee_hrn, delegatee_type))
- with file(filename,'w') as f:
+ with file(filename, 'w') as f:
f.write(delegated_credential)
self.logger.debug("(Over)wrote {}".format(filename))
hrn_delegated_credentials.append ((hrn, htype, delegated_credential, filename, ))
username=myslice_dict['username'],
password=options.password)
uploader.prompt_all()
- (count_all,count_success)=(0,0)
- for (hrn,htype,delegated_credential,filename) in hrn_delegated_credentials:
+ (count_all, count_success) = (0, 0)
+ for (hrn, htype, delegated_credential, filename) in hrn_delegated_credentials:
# inspect
- inspect=Credential(string=delegated_credential)
- expire_datetime=inspect.get_expiration()
- message="{} ({}) [exp:{}]".format(hrn, htype, expire_datetime)
- if uploader.upload(delegated_credential,message=message):
- count_success+=1
- count_all+=1
+ inspect = Credential(string=delegated_credential)
+ expire_datetime = inspect.get_expiration()
+ message = "{} ({}) [exp:{}]".format(hrn, htype, expire_datetime)
+ if uploader.upload(delegated_credential, message=message):
+ count_success += 1
+ count_all += 1
self.logger.info("Successfully uploaded {}/{} credentials"
.format(count_success, count_all))
# like 'sfi delegate does' but on second thought
# it is probably not helpful as people would not
# need to run 'sfi delegate' at all anymore
- if count_success != count_all: sys.exit(1)
+ if count_success != count_all:
+ sys.exit(1)
# xxx should analyze result
return 0
- @declare_command("cred","")
+ @declare_command("cred", "")
def trusted(self, options, args):
"""
return the trusted certs at this interface (get_trusted_certs)
"""
if options.registry_interface:
- server=self.registry()
+ server = self.registry()
else:
server = self.sliceapi()
cred = self.my_authority_credential_string()
trusted_certs = ReturnValue.get_value(trusted_certs)
for trusted_cert in trusted_certs:
- print "\n===========================================================\n"
+ print("\n===========================================================\n")
gid = GID(string=trusted_cert)
gid.dump()
cert = Certificate(string=trusted_cert)
self.logger.debug('Sfi.trusted -> {}'.format(cert.get_subject()))
- print "Certificate:\n{}\n\n".format(trusted_cert)
+ print("Certificate:\n{}\n\n".format(trusted_cert))
# xxx should analyze result
return 0
#!/usr/bin/python
+
+from __future__ import print_function
+
from datetime import datetime, timedelta
from sfa.util.xml import XML, XpathFilter
input = sys.argv[1]
with open(input) as f:
rspec = RSpec(f.read())
- print rspec
+ print(rspec)
# rspec.register_rspec_element(RSpecElements.NETWORK, 'network', '//network')
# rspec.register_rspec_element(RSpecElements.NODE, 'node', '//node')
# print rspec.get(RSpecElements.NODE)[0]
# @param cert_file certificate filename containing public key
# (could be a GID file)
- def __init__(self, ip, port, key_file, cert_file,interface):
+ def __init__(self, ip, port, key_file, cert_file, interface):
threading.Thread.__init__(self)
self.key = Keypair(filename = key_file)
self.cert = Certificate(filename = cert_file)
logger.error ("checkCredentialsSpeaksFor was not passed options=options")
return
# remove the options arg
- options=kwds['options']; del kwds['options']
+ options = kwds['options']; del kwds['options']
# compute the speaking_for_xrn arg and pass it to checkCredentials
- if options is None: speaking_for_xrn=None
- else: speaking_for_xrn=options.get('geni_speaking_for',None)
- kwds['speaking_for_xrn']=speaking_for_xrn
- return self.checkCredentials (*args, **kwds)
+ if options is None: speaking_for_xrn = None
+ else: speaking_for_xrn = options.get('geni_speaking_for', None)
+ kwds['speaking_for_xrn'] = speaking_for_xrn
+ return self.checkCredentials(*args, **kwds)
# do not use mutable as default argument
# http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments
def checkCredentials(self, creds, operation, xrns=None,
check_sliver_callback=None,
speaking_for_xrn=None):
- if xrns is None: xrns=[]
+ if xrns is None: xrns = []
+ error = (None, None)
def log_invalid_cred(cred):
if not isinstance (cred, StringTypes):
logger.info("cannot validate credential %s - expecting a string"%cred)
- error="checkCredentials: expected a string, received %s"%(type(cred))
+ error = ('TypeMismatch',
+ "checkCredentials: expected a string, received {} -- {}"
+ .format(type(cred), cred))
else:
- cred_obj=Credential(string=cred)
+ cred_obj = Credential(string=cred)
logger.info("failed to validate credential - dump=%s"%\
cred_obj.dump_string(dump_parents=True))
error = sys.exc_info()[:2]
# won't work if either creds or hrns is empty - let's make it more explicit
if not creds: raise Forbidden("no credential provided")
if not hrns: hrns = [None]
- error=[None,None]
speaks_for_gid = determine_speaks_for(logger, creds, self.peer_cert,
speaking_for_xrn, self.trusted_cert_list)
return valid
-
def check(self, credential, operation, hrn = None):
"""
Check the credential against the peer cert (callerGID) included
# researchers in the slice are in the DB as-is
researcher_hrns = [ user.hrn for user in reg_record.reg_researchers ]
# locating PIs attached to that slice
- slice_pis=reg_record.get_pis()
+ slice_pis = reg_record.get_pis()
pi_hrns = [ user.hrn for user in slice_pis ]
if (caller_hrn in researcher_hrns + pi_hrns):
rl.add('refresh')
def create(self):
self.key = crypto.PKey()
- self.key.generate_key(crypto.TYPE_RSA, 1024)
+ self.key.generate_key(crypto.TYPE_RSA, 2048)
##
# Save the private key to a file
def load_from_string(self, string):
if glo_passphrase_callback:
- self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, string, functools.partial(glo_passphrase_callback, self, string) )
- self.m2key = M2Crypto.EVP.load_key_string(string, functools.partial(glo_passphrase_callback, self, string) )
+ self.key = crypto.load_privatekey(
+ crypto.FILETYPE_PEM, string, functools.partial(glo_passphrase_callback, self, string))
+ self.m2key = M2Crypto.EVP.load_key_string(
+ string, functools.partial(glo_passphrase_callback, self, string))
else:
self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, string)
self.m2key = M2Crypto.EVP.load_key_string(string)
# prob not necc since this cert itself is junk but still...
m2x509.set_version(2)
junk_key = Keypair(create=True)
- m2x509.sign(pkey=junk_key.get_m2_pkey(), md="sha1")
+ m2x509.sign(pkey=junk_key.get_m2_pubkey(), md="sha1")
# convert the m2 x509 cert to a pyopenssl x509
m2pem = m2x509.as_pem()
##
# Return an M2Crypto key object
- def get_m2_pkey(self):
+ def get_m2_pubkey(self):
if not self.m2key:
self.m2key = M2Crypto.EVP.load_key_string(self.as_pem())
return self.m2key
# Returns a string containing the public key represented by this object.
def get_pubkey_string(self):
- m2pkey = self.get_m2_pkey()
+ m2pkey = self.get_m2_pubkey()
return base64.b64encode(m2pkey.as_der())
##
return self.as_pem() == pkey.as_pem()
def sign_string(self, data):
- k = self.get_m2_pkey()
+ k = self.get_m2_pubkey()
k.sign_init()
k.sign_update(data)
return base64.b64encode(k.sign_final())
def verify_string(self, data, sig):
- k = self.get_m2_pkey()
+ k = self.get_m2_pubkey()
k.verify_init()
k.verify_update(data)
return M2Crypto.m2.verify_final(k.ctx, base64.b64decode(sig), k.pkey)
# whether to save the parent certificates as well.
class Certificate:
- digest = "md5"
+ digest = "sha256"
# x509 = None
# issuerKey = None
# if it is a chain of multiple certs, then split off the first one and
# load it (support for the ---parent--- tag as well as normal chained certs)
+ if string is None or string.strip() == "":
+ logger.warn("Empty string in load_from_string")
+ return
+
string = string.strip()
# If it's not in proper PEM format, wrap it
self.x509 = crypto.load_certificate(crypto.FILETYPE_PEM, parts[0])
+ if self.x509 is None:
+ logger.warn("Loaded from string but cert is None: %s" % string)
+
# if there are more certs, then create a parent and let the parent load
# itself from the remainder of the string
if len(parts) > 1 and parts[1] != '':
# @param save_parents If save_parents==True, then also save the parent certificates.
def save_to_string(self, save_parents=True):
+ if self.x509 is None:
+ logger.warn("None cert in certificate.save_to_string")
+ return ""
string = crypto.dump_certificate(crypto.FILETYPE_PEM, self.x509)
if save_parents and self.parent:
string = string + self.parent.save_to_string(save_parents)
##
# Get a pretty-print subject name of the certificate
# let's try to make this a little more usable as is makes logs hairy
+ # FIXME: Consider adding 'urn:publicid' and 'uuid' back for GENI?
pretty_fields = ['email']
def filter_chunk(self, chunk):
for field in self.pretty_fields:
def get_extension(self, name):
+ if name is None:
+ return None
+
+ certstr = self.save_to_string()
+ if certstr is None or certstr == "":
+ return None
# pyOpenSSL does not have a way to get extensions
- m2x509 = X509.load_cert_string(self.save_to_string())
+ m2x509 = X509.load_cert_string(certstr)
+ if m2x509 is None:
+ logger.warn("No cert loaded in get_extension")
+ return None
+ if m2x509.get_ext(name) is None:
+ return None
value = m2x509.get_ext(name).get_value()
return value
# @param pkey is a Keypair object representing a public key. If Pkey
# did not sign the certificate, then an exception will be thrown.
- def verify(self, pkey):
+ def verify(self, pubkey):
# pyOpenSSL does not have a way to verify signatures
m2x509 = X509.load_cert_string(self.save_to_string())
- m2pkey = pkey.get_m2_pkey()
+ m2pubkey = pubkey.get_m2_pubkey()
# verify it
- return m2x509.verify(m2pkey)
+ # verify returns -1 or 0 on failure depending on how serious the
+ # error conditions are
+ return m2x509.verify(m2pubkey) == 1
# XXX alternatively, if openssl has been patched, do the much simpler:
# try:
if self.is_signed_by_cert(trusted_cert):
# verify expiration of trusted_cert ?
if not trusted_cert.x509.has_expired():
- if debug_verify_chain:
+ if debug_verify_chain:
logger.debug("verify_chain: YES. Cert %s signed by trusted cert %s"%(
self.pretty_cert(), trusted_cert.pretty_cert()))
return trusted_cert
if not self.is_signed_by_cert(self.parent):
if debug_verify_chain:
logger.debug("verify_chain: NO. %s is not signed by parent %s, but by %s"%\
- (self.pretty_cert(),
- self.parent.pretty_cert(),
+ (self.pretty_cert(),
+ self.parent.pretty_cert(),
self.get_issuer()))
raise CertNotSignedByParent("%s: Parent %s, issuer %s"\
- % (self.pretty_cert(),
+ % (self.pretty_cert(),
self.parent.pretty_cert(),
self.get_issuer()))
from sfa.util.xrn import urn_to_hrn, hrn_authfor_hrn
# 31 days, in seconds
-DEFAULT_CREDENTIAL_LIFETIME = 86400 * 28
+DEFAULT_CREDENTIAL_LIFETIME = 86400 * 31
# TODO:
logger.log_exc ("Failed to parse credential, %s"%self.xml)
raise
sig = doc.getElementsByTagName("Signature")[0]
- self.set_refid(sig.getAttribute("xml:id").strip("Sig_"))
- keyinfo = sig.getElementsByTagName("X509Data")[0]
- szgid = getTextNode(keyinfo, "X509Certificate")
- szgid = "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----" % szgid
- self.set_issuer_gid(GID(string=szgid))
+ ## This code until the end of function rewritten by Aaron Helsinger
+ 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))
def encode(self):
self.xml = signature_template % (self.get_refid(), self.get_refid())
for cred in creds:
try:
tmp_cred = Credential(string=cred)
+ if tmp_cred.type != Credential.SFA_CREDENTIAL_TYPE:
+ continue
if tmp_cred.get_gid_caller().get_hrn() in caller_hrn_list:
caller_creds.append(cred)
except: pass
class Credential(object):
+ SFA_CREDENTIAL_TYPE = "geni_sfa"
+
##
# Create a Credential object
#
self.signature = None
self.xml = None
self.refid = None
- self.type = None
+ self.type = Credential.SFA_CREDENTIAL_TYPE
self.version = None
if cred:
if isinstance(cred, StringTypes):
string = cred
- self.type = 'geni_sfa'
- self.version = '1.0'
+ self.type = Credential.SFA_CREDENTIAL_TYPE
+ self.version = '3'
elif isinstance(cred, dict):
string = cred['geni_value']
self.type = cred['geni_type']
self.version = cred['geni_version']
-
if string or filename:
if string:
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
+ # not strictly necessary but won't hurt either
+ self.get_xmlsec1_path()
+
+ @staticmethod
+ def get_xmlsec1_path():
+ if not getattr(Credential, 'xmlsec1_path', None):
+ # Find a xmlsec1 binary path
+ Credential.xmlsec1_path = ''
+ paths = ['/usr/bin', '/usr/local/bin', '/bin', '/opt/bin', '/opt/local/bin']
+ try: paths += os.getenv('PATH').split(':')
+ except: pass
+ for path in paths:
+ xmlsec1 = os.path.join(path, 'xmlsec1')
+ if os.path.isfile(xmlsec1):
+ Credential.xmlsec1_path = xmlsec1
+ break
+ if not Credential.xmlsec1_path:
+ logger.error("Could not locate required binary 'xmlsec1' - SFA will be unable to sign stuff !!")
+ return Credential.xmlsec1_path
+
+ def get_subject(self):
+ if not self.gidObject:
+ self.decode()
+ return self.gidObject.get_subject()
def pretty_subject(self):
subject = ""
# 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")
+ # 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)
logger.debug("Creating credential valid for %s s"%DEFAULT_CREDENTIAL_LIFETIME)
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 - by Aaron Helsinger
+ self.expiration = self.expiration.astimezone(tz.tzutc())
append_sub(doc, cred, "expires", self.expiration.strftime(SFATIME_FORMAT))
privileges = doc.createElement("privileges")
cred.appendChild(privileges)
signatures.appendChild(ele)
# Get the finished product
- self.xml = doc.toxml()
+ self.xml = doc.toxml("utf-8")
def save_to_random_tmp_file(self):
# you have loaded an existing signed credential, do not call encode() or sign() on it.
def sign(self):
- if not self.issuer_privkey or not self.issuer_gid:
+ if not self.issuer_privkey:
+ logger.warn("Cannot sign credential (no private key)")
+ return
+ if not self.issuer_gid:
+ logger.warn("Cannot sign credential (no issuer gid)")
return
doc = parseString(self.get_xml())
sigs = doc.getElementsByTagName("signatures")[0]
sig_ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
sigs.appendChild(sig_ele)
- self.xml = doc.toxml()
+ self.xml = doc.toxml("utf-8")
# Split the issuer GID into multiple certificates if it's a chain
# Call out to xmlsec1 to sign it
ref = 'Sig_%s' % self.get_refid()
filename = self.save_to_random_tmp_file()
- signed = os.popen('%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
- % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)).read()
+ xmlsec1 = self.get_xmlsec1_path()
+ if not xmlsec1:
+ raise Exception("Could not locate required 'xmlsec1' program")
+ command = '%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
+ % (xmlsec1, ref, self.issuer_privkey, ",".join(gid_files), filename)
+# print 'command',command
+ signed = os.popen(command).read()
os.remove(filename)
for gid_file in gid_files:
# Update signatures
self.decode()
-
+
##
# Retrieve the attributes of the credential from the XML.
# This is automatically called by the various get_* methods of
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"))
+ self.gidObject = GID(string=getTextNode(cred, "target_gid"))
+ ## This code until the end of function rewritten by Aaron Helsinger
# 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))
+ 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)
parent = cred.getElementsByTagName("parent")
if len(parent) > 0:
parent_doc = parent[0].getElementsByTagName("credential")[0]
- parent_xml = parent_doc.toxml()
+ 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())
+ Sig = Signature(string=sig.toxml("utf-8"))
for cur_cred in self.get_credential_list():
if cur_cred.get_refid() == Sig.get_refid():
#cert_args = " ".join(['--trusted-pem %s' % x for x in trusted_certs])
#command = '{} --verify --node-id "{}" {} {} 2>&1'.\
# format(self.xmlsec_path, ref, cert_args, filename)
- command = [ self.xmlsec_path, '--verify', '--node-id', ref ]
+ xmlsec1 = self.get_xmlsec1_path()
+ if not xmlsec1:
+ raise Exception("Could not locate required 'xmlsec1' program")
+ command = [ xmlsec1, '--verify', '--node-id', ref ]
for trusted in trusted_certs:
command += ["--trusted-pem", trusted ]
command += [ filename ]
def verify_issuer(self, trusted_gids):
root_cred = self.get_credential_list()[-1]
root_target_gid = root_cred.get_gid_object()
+ if root_cred.get_signature() is None:
+ # malformed
+ raise CredentialNotVerifiable("Could not verify credential owned by %s for object %s. Cred has no signature" % (self.gidCaller.get_urn(), self.gidObject.get_urn()))
+
root_cred_signer = root_cred.get_signature().get_issuer_gid()
# Case 1:
# only informative
def get_filename(self):
return getattr(self,'filename',None)
-
+
def actual_caller_hrn (self):
"""a helper method used by some API calls like e.g. Allocate
to try and find out who really is the original caller
-
+
This admittedly is a bit of a hack, please USE IN LAST RESORT
-
+
This code uses a heuristic to identify a delegated credential
A first known restriction if for traffic that gets through a slice manager
subject_hrn = self.get_gid_object().get_hrn()
# if we find that the caller_hrn is an immediate descendant of the issuer, then
# this seems to be a 'regular' credential
- if caller_hrn.startswith(issuer_hrn):
+ if caller_hrn.startswith(issuer_hrn):
actual_caller_hrn=caller_hrn
# else this looks like a delegated credential, and the real caller is the issuer
else:
logger.info("actual_caller_hrn: caller_hrn=%s, issuer_hrn=%s, returning %s"
%(caller_hrn,issuer_hrn,actual_caller_hrn))
return actual_caller_hrn
-
+
##
# Dump the contents of a credential to stdout in human-readable format
#
def dump (self, *args, **kwargs):
print self.dump_string(*args, **kwargs)
- # show_xml is ignored
- def dump_string(self, dump_parents=False, show_xml=None):
+ # SFA code ignores show_xml and disables printing the cred xml
+ def dump_string(self, dump_parents=False, show_xml=False):
result=""
result += "CREDENTIAL %s\n" % self.pretty_subject()
filename=self.get_filename()
if privileges:
result += " privs: %s\n" % privileges.save_to_string()
else:
- result += " privs: \n"
+ result += " privs: \n"
gidCaller = self.get_gid_caller()
if gidCaller:
result += " gidCaller:\n"
result += gidCaller.dump_string(8, dump_parents)
if self.get_signature():
- print " gidIssuer:"
- self.get_signature().get_issuer_gid().dump(8, dump_parents)
+ result += " gidIssuer:\n"
+ result += self.get_signature().get_issuer_gid().dump_string(8, dump_parents)
if self.expiration:
- print " expiration:", self.expiration.strftime(SFATIME_FORMAT)
+ result += " expiration: " + self.expiration.strftime(SFATIME_FORMAT) + "\n"
gidObject = self.get_gid_object()
if gidObject:
result += "\nPARENT"
result += self.parent.dump_string(True)
+ if show_xml and HAVELXML:
+ try:
+ tree = etree.parse(StringIO(self.xml))
+ aside = etree.tostring(tree, pretty_print=True)
+ result += "\nXML:\n\n"
+ result += aside
+ result += "\nEnd XML\n"
+ except:
+ import traceback
+ print "exc. Credential.dump_string / XML"
+ traceback.print_exc()
+
return result
# IN THE WORK.
#----------------------------------------------------------------------
+from __future__ import print_function
+
import datetime
from dateutil import parser as du_parser, tz as du_tz
import optparse
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:
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:
if not isinstance(cred_value, ABACCredential):
cred = CredentialFactory.createCred(cred_value)
-# print "Got a cred to check speaksfor for: %s" % cred.pretty_cred()
+# 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()
cred.sign()
# Save it
cred.save_to_file(cred_filename)
- print "Created ABAC credential: '%s' in file %s" % \
- (cred.pretty_cred(), 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()
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
# --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)
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
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())
def get_file_list(self):
file_list = []
- pattern=os.path.join(self.basedir,"*")
+ pattern = os.path.join(self.basedir,"*")
for cert_file in glob.glob(pattern):
if os.path.isfile(cert_file):
if self.has_supported_extension(cert_file):
file_list.append(cert_file)
else:
- logger.warning("File %s ignored - supported extensions are %r"%\
- (cert_file,TrustedRoots.supported_extensions))
+ logger.warning("File {} ignored - supported extensions are {}"
+ .format(cert_file, TrustedRoots.supported_extensions))
return file_list
def has_supported_extension (self,path):
return result
- except SfaFault, fault:
+ except SfaFault as fault:
caller = ""
try:
handler=logging.handlers.RotatingFileHandler(logfile,maxBytes=1000000, backupCount=5)
except IOError:
- # This is usually a permissions error becaue the file is
+ # This is usually a permissions error because the file is
# owned by root, but httpd is trying to access it.
- tmplogfile=os.getenv("TMPDIR", "/tmp") + os.path.sep + os.path.basename(logfile)
+ tmplogfile=os.path.join(os.getenv("TMPDIR", os.getenv("TMP", os.path.normpath("/tmp"))), os.path.basename(logfile))
+ tmplogfile = os.path.normpath(tmplogfile)
+
+ tmpdir = os.path.dirname(tmplogfile)
+ if tmpdir and tmpdir != "" and not os.path.exists(tmpdir):
+ os.makedirs(tmpdir)
+
# In strange uses, 2 users on same machine might use same code,
# meaning they would clobber each others files
# We could (a) rename the tmplogfile, or (b)
# are redirected on self.element
def __getattr__ (self, name):
if not hasattr(self.element, name):
- raise AttributeError, name
+ raise AttributeError(name)
return getattr(self.element, name)
class XML:
# 'rspec' file doesnt exist. 'rspec' is proably an xml string
try:
tree = etree.parse(StringIO(xml), parser)
- except Exception, e:
+ except Exception as e:
raise InvalidXML(str(e))
root = tree.getroot()
self.namespaces = dict(root.nsmap)