Merge branch 'geni-v3' of ssh://git.onelab.eu/git/sfa into geni-v3
authorfsaintma <frederic.saint-marcel@inria.fr>
Fri, 18 Dec 2015 12:41:16 +0000 (13:41 +0100)
committerfsaintma <frederic.saint-marcel@inria.fr>
Fri, 18 Dec 2015 12:41:16 +0000 (13:41 +0100)
15 files changed:
init.d/sfa
sfa.spec
sfa/client/manifolduploader.py
sfa/client/sfaserverproxy.py
sfa/client/sfi.py
sfa/rspecs/rspec.py
sfa/server/sfaserver.py
sfa/trust/auth.py
sfa/trust/certificate.py
sfa/trust/credential.py
sfa/trust/speaksfor_util.py
sfa/trust/trustedroots.py
sfa/util/method.py
sfa/util/sfalogging.py
sfa/util/xml.py

index e3b80f9..d77a58d 100755 (executable)
@@ -234,14 +234,14 @@ function db_start () {
 
     ######## 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
        
index a21779d..39aa494 100644 (file)
--- a/sfa.spec
+++ b/sfa.spec
@@ -1,6 +1,6 @@
 %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)" )
@@ -253,6 +253,16 @@ fi
 #[ "$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
 
index 8354e1e..c291a42 100755 (executable)
@@ -27,7 +27,8 @@ DEFAULT_PLATFORM = 'ple'
 
 # 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
@@ -82,11 +83,9 @@ class ManifoldUploader:
 #        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
index 615a8b6..d326b3a 100644 (file)
@@ -2,7 +2,8 @@
 
 # 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
@@ -48,13 +49,9 @@ class XMLRPCTransport(xmlrpclib.Transport):
         # 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
@@ -85,13 +82,9 @@ class XMLRPCServerProxy(xmlrpclib.ServerProxy):
         # 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))
index 3fc44da..6887250 100644 (file)
@@ -3,6 +3,8 @@
 # this module is also used in sfascan
 #
 
+from __future__ import print_function
+
 import sys
 sys.path.append('.')
 
@@ -67,12 +69,12 @@ def display_rspec(rspec, format='rspec'):
     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'''
@@ -84,7 +86,7 @@ def display_record(record, dump=False):
         record.dump(sort=True)
     else:
         info = record.getdict()
-        print "{} ({})".format(info['hrn'], info['type'])
+        print("{} ({})".format(info['hrn'], info['type']))
     return
 
 
@@ -98,7 +100,7 @@ def filter_records(type, records):
 
 def credential_printable (cred):
     credential = Credential(cred=cred)
-    result=""
+    result = ""
     result += credential.pretty_cred()
     result += "\n"
     rights = credential.get_privileges()
@@ -108,9 +110,9 @@ def credential_printable (cred):
     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
 
@@ -121,7 +123,7 @@ def save_raw_to_file(var, filename, format='text', banner=None):
     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":
@@ -134,7 +136,7 @@ def _save_raw_to_file(var, f, format, banner):
         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):
@@ -142,14 +144,14 @@ 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":
@@ -162,18 +164,18 @@ def save_records_to_file(filename, record_dicts, 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):
@@ -195,7 +197,7 @@ def normalize_type (type):
     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):
@@ -214,7 +216,7 @@ 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
@@ -257,14 +259,14 @@ from functools import wraps
 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:
@@ -277,7 +279,7 @@ def declare_command (args_string, example,aliases=None):
 
 
 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]
 
 ##########
@@ -299,11 +301,13 @@ class Sfi:
     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
@@ -312,55 +316,55 @@ class Sfi:
         ### 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
@@ -413,7 +417,7 @@ class Sfi:
             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] {}"\
@@ -551,7 +555,7 @@ use this if you mean an authority instead""")
         (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':
@@ -582,7 +586,7 @@ use this if you mean an authority instead""")
             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:
@@ -611,8 +615,8 @@ use this if you mean an authority instead""")
     
     ####################
     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)
@@ -637,13 +641,13 @@ use this if you mean an authority instead""")
         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):
@@ -681,7 +685,7 @@ use this if you mean an authority instead""")
            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)
 
@@ -770,7 +774,7 @@ use this if you mean an authority instead""")
         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)
@@ -792,7 +796,7 @@ use this if you mean an authority instead""")
         # 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)
@@ -801,7 +805,7 @@ use this if you mean an authority instead""")
                     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://'):
@@ -816,7 +820,7 @@ use this if you mean an authority instead""")
         # 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)
@@ -829,9 +833,9 @@ use this if you mean an authority instead""")
 
         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)
 
@@ -906,13 +910,13 @@ use this if you mean an authority instead""")
     # 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
 
     #==========================================================================
@@ -921,43 +925,43 @@ use this if you mean an authority instead""")
     # 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()
@@ -970,12 +974,12 @@ use this if you mean an authority instead""")
         # 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]
@@ -988,7 +992,7 @@ use this if you mean an authority instead""")
         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...
@@ -999,18 +1003,19 @@ use this if you mean an authority instead""")
         # 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:
@@ -1019,23 +1024,23 @@ use this if you mean an authority instead""")
         # 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) 
@@ -1048,13 +1053,13 @@ use this if you mean an authority instead""")
         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())
@@ -1075,7 +1080,7 @@ use this if you mean an authority instead""")
         # 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) 
@@ -1102,7 +1107,7 @@ use this if you mean an authority instead""")
         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]:
@@ -1123,11 +1128,11 @@ use this if you mean an authority instead""")
         # 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]
@@ -1147,7 +1152,7 @@ use this if you mean an authority instead""")
     # ==================================================================
 
     # show rspec for named slice
-    @declare_command("","",['discover'])
+    @declare_command("", "", ['discover'])
     def resources(self, options, args):
         """
         discover available resources (ListResources)
@@ -1184,9 +1189,10 @@ use this if you mean an authority instead""")
                 # 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:
@@ -1197,7 +1203,7 @@ use this if you mean an authority instead""")
             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 
@@ -1241,7 +1247,7 @@ use this if you mean an authority instead""")
             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)
@@ -1273,10 +1279,10 @@ use this if you mean an authority instead""")
         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)
@@ -1315,7 +1321,7 @@ use this if you mean an authority instead""")
         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]
@@ -1335,10 +1341,10 @@ use this if you mean an authority instead""")
         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)
@@ -1385,7 +1391,7 @@ use this if you mean an authority instead""")
         #  }]
         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]
@@ -1400,10 +1406,10 @@ use this if you mean an authority instead""")
         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)
@@ -1420,18 +1426,18 @@ use this if you mean an authority instead""")
 
         # 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
@@ -1460,7 +1466,7 @@ use this if you mean an authority instead""")
         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",
@@ -1494,20 +1500,20 @@ use this if you mean an authority instead""")
         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)
@@ -1524,10 +1530,10 @@ use this if you mean an authority instead""")
         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)
@@ -1548,7 +1554,7 @@ use this if you mean an authority instead""")
         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
@@ -1579,7 +1585,7 @@ use this if you mean an authority instead""")
             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,) )
@@ -1588,7 +1594,8 @@ use this if you mean an authority instead""")
             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)
@@ -1596,12 +1603,11 @@ use this if you mean an authority instead""")
             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,
@@ -1611,7 +1617,7 @@ use this if you mean an authority instead""")
                              .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
@@ -1656,30 +1662,30 @@ $ sfi m -b http://mymanifold.foo.com:7080/
         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']
@@ -1692,7 +1698,7 @@ $ sfi m -b http://mymanifold.foo.com:7080/
             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))
  
@@ -1703,7 +1709,7 @@ $ sfi m -b http://mymanifold.foo.com:7080/
             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),) )
@@ -1713,8 +1719,8 @@ $ sfi m -b http://mymanifold.foo.com:7080/
         # (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)
@@ -1722,7 +1728,7 @@ $ sfi m -b http://mymanifold.foo.com:7080/
             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, ))
@@ -1737,15 +1743,15 @@ $ sfi m -b http://mymanifold.foo.com:7080/
                                      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))
 
@@ -1753,17 +1759,18 @@ $ sfi m -b http://mymanifold.foo.com:7080/
         # 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()
@@ -1772,11 +1779,11 @@ $ sfi m -b http://mymanifold.foo.com:7080/
             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
index 635ea23..372a835 100755 (executable)
@@ -1,4 +1,7 @@
 #!/usr/bin/python 
+
+from __future__ import print_function
+
 from datetime import datetime, timedelta
 
 from sfa.util.xml import XML, XpathFilter
@@ -133,7 +136,7 @@ if __name__ == '__main__':
     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]
index b1e8d33..8e7c5f8 100644 (file)
@@ -31,7 +31,7 @@ class SfaServer(threading.Thread):
     # @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)
index e852e19..86d5d4f 100644 (file)
@@ -47,25 +47,28 @@ class Auth:
             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]
@@ -94,7 +97,6 @@ class Auth:
         # 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)
@@ -124,7 +126,6 @@ class Auth:
         
         return valid
         
-        
     def check(self, credential, operation, hrn = None):
         """
         Check the credential against the peer cert (callerGID) included 
@@ -328,7 +329,7 @@ class Auth:
             # 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')
index c3f3790..ff6534e 100644 (file)
@@ -151,7 +151,7 @@ class Keypair:
 
     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
@@ -174,8 +174,10 @@ class Keypair:
 
     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)
@@ -205,7 +207,7 @@ class Keypair:
         # 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()
@@ -234,7 +236,7 @@ class Keypair:
     ##
     # 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
@@ -243,7 +245,7 @@ class Keypair:
     # 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())
 
     ##
@@ -259,13 +261,13 @@ class Keypair:
         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)
@@ -300,7 +302,7 @@ class Keypair:
 # whether to save the parent certificates as well.
 
 class Certificate:
-    digest = "md5"
+    digest = "sha256"
 
 #    x509 = None
 #    issuerKey = None
@@ -367,6 +369,10 @@ class Certificate:
         # 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
@@ -391,6 +397,9 @@ class Certificate:
 
         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] != '':
@@ -412,6 +421,9 @@ class Certificate:
     # @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)
@@ -498,6 +510,7 @@ class Certificate:
     ##
     # 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:
@@ -601,8 +614,19 @@ class Certificate:
 
     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
@@ -651,12 +675,14 @@ class Certificate:
     # @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:
@@ -734,7 +760,7 @@ class Certificate:
             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
@@ -757,11 +783,11 @@ class Certificate:
         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()))
 
index 66401f8..3f658fb 100644 (file)
@@ -51,7 +51,7 @@ from sfa.trust.gid import GID
 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:
@@ -187,11 +187,32 @@ class Signature(object):
             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())
@@ -221,6 +242,8 @@ def filter_creds_by_caller(creds, caller_hrn_list):
         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
@@ -228,6 +251,8 @@ def filter_creds_by_caller(creds, caller_hrn_list):
 
 class Credential(object):
 
+    SFA_CREDENTIAL_TYPE = "geni_sfa"
+
     ##
     # Create a Credential object
     #
@@ -248,19 +273,18 @@ class 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:                
@@ -275,14 +299,30 @@ class Credential(object):
             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 = ""
@@ -434,12 +474,13 @@ class Credential(object):
         # 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)  
         
@@ -458,6 +499,9 @@ class Credential(object):
             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)
@@ -536,7 +580,7 @@ class Credential(object):
                 signatures.appendChild(ele)
                 
         # Get the finished product
-        self.xml = doc.toxml()
+        self.xml = doc.toxml("utf-8")
 
 
     def save_to_random_tmp_file(self):       
@@ -615,7 +659,11 @@ class Credential(object):
     # 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]
@@ -627,7 +675,7 @@ class Credential(object):
         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
@@ -644,8 +692,13 @@ class Credential(object):
         # 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:
@@ -656,7 +709,7 @@ class Credential(object):
         # Update signatures
         self.decode()       
 
-        
+
     ##
     # Retrieve the attributes of the credential from the XML.
     # This is automatically called by the various get_* methods of
@@ -694,25 +747,28 @@ class Credential(object):
         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)
 
 
@@ -720,13 +776,15 @@ class Credential(object):
         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():
@@ -835,7 +893,10 @@ class Credential(object):
             #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 ]
@@ -891,6 +952,10 @@ class Credential(object):
     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:
@@ -1051,13 +1116,13 @@ class Credential(object):
     # 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
@@ -1069,7 +1134,7 @@ class Credential(object):
         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:
@@ -1077,7 +1142,7 @@ class Credential(object):
         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
     #
@@ -1085,8 +1150,8 @@ class Credential(object):
     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()
@@ -1095,18 +1160,18 @@ class Credential(object):
         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:
@@ -1117,4 +1182,16 @@ class Credential(object):
             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
index eaeecf0..9bad61d 100644 (file)
@@ -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
@@ -38,6 +40,7 @@ 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:
@@ -167,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:
@@ -252,27 +258,24 @@ def determine_speaks_for(logger, credentials, caller_gid, speaking_for_xrn, trus
             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()
@@ -303,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.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()
 
@@ -356,9 +358,9 @@ def create_speaks_for(tool_gid, user_gid, ma_gid, \
 
     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
@@ -366,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)
 
 
@@ -413,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
@@ -434,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())
index a505aea..fb6b642 100644 (file)
@@ -27,14 +27,14 @@ class TrustedRoots:
 
     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):
index eb3cba5..e7bdee7 100644 (file)
@@ -84,7 +84,7 @@ class Method:
 
             return result
 
-        except SfaFault, fault:
+        except SfaFault as fault:
 
             caller = ""
 
index 61d76a6..361a243 100644 (file)
@@ -48,9 +48,15 @@ class _SfaLogger:
         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)
index ba324c7..f46443a 100755 (executable)
@@ -153,7 +153,7 @@ class XmlElement:
     # 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:
@@ -182,7 +182,7 @@ 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)