Changeset e83f2f2


Ignore:
Timestamp:
Dec 14, 2010 6:58:28 PM (13 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
c092b7f
Parents:
2627eb3
Message:

Move proofs around. Lots of changes, including fault handling.

Files:
1 added
24 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd_create.py

    r2627eb3 re83f2f2  
    99from string import join
    1010
     11from federation.proof import proof
    1112from federation.fedid import fedid, generate_fedid
    1213from federation.remote_service import service_caller
    1314from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    1415        wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,\
    15         get_abac_certs
     16        get_abac_certs, log_authentication
    1617from federation.util import abac_split_cert, abac_context_to_creds
    1718from federation import topdl
     
    247248            caller=service_caller('New'), responseBody="NewResponseBody")
    248249except RPCException, e:
    249     exit_with_fault(e)
     250    exit_with_fault(e, 'New (create)', opts)
    250251except RuntimeError, e:
    251252    sys.exit("Error processing RPC: %s" % e)
     
    253254if opts.debug > 1: print >>sys.stderr, resp_dict
    254255
     256proof = proof.from_dict(resp_dict.get('proof', {}))
     257if proof and opts.auth_log:
     258    log_authentication(opts.auth_log, 'New (create)', 'succeeded', proof)
    255259# Save the experiment ID certificate if we need it
    256260try:
     
    303307            serialize_only=opts.serialize_only,
    304308            tracefile=opts.tracefile,
    305             caller=service_caller('Create'), responseBody="CreateResponseBody")
     309            caller=service_caller('Create', max_retries=1), responseBody="CreateResponseBody")
    306310except RPCException, e:
    307     exit_with_fault(e)
     311    exit_with_fault(e, 'Create', opts)
    308312except RuntimeError, e:
    309313    sys.exit("Error processing RPC: %s" % e)
     
    318322if e_fedid: print "fedid: %s" % e_fedid
    319323if st: print "status: %s" % st
    320 
     324proof = proof.from_dict(resp_dict.get('proof', {}))
     325if proof and opts.auth_log:
     326    log_authentication(opts.auth_log, 'Create', 'succeeded', proof)
  • fedd/fedd_ftopo.py

    r2627eb3 re83f2f2  
    44
    55from federation import topdl
     6from federation.proof import proof
    67from federation.remote_service import service_caller
    78from federation.client_lib import client_opts, exit_with_fault, RPCException,\
    8         wrangle_standard_options, do_rpc, get_experiment_names, info_format
     9        wrangle_standard_options, do_rpc, get_experiment_names, info_format, \
     10        log_authentication
    911
    1012class ftopo_opts(client_opts):
     
    4244            caller=service_caller('Info'), responseBody='InfoResponseBody')
    4345except RPCException, e:
    44     exit_with_fault(e)
     46    exit_with_fault(e, 'Ftopo', opts)
    4547except RuntimeError, e:
    4648    sys.exit("Error processing RPC: %s" % e)
     
    6567else:
    6668    sys.exit("Badly formatted response (no experiment descrption)!?")
     69proof = proof.from_dict(resp_dict.get('proof', {}))
     70if proof and opts.auth_log:
     71    log_authentication(opts.auth_log, 'Ftopo', 'succeeded', proof)
  • fedd/fedd_image.py

    r2627eb3 re83f2f2  
    88
    99from federation import topdl
     10from federation.proof import proof
    1011from federation.remote_service import service_caller
    1112from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    12         wrangle_standard_options, do_rpc, get_experiment_names, save_certfile
     13        wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,\
     14        log_authentication
    1315
    1416
     
    296298            caller=service_caller('Info'), responseBody="InfoResponseBody")
    297299
     300    proof = proof.from_dict(resp_dict.get('proof', {}))
     301    if proof and opts.auth_log:
     302        log_authentication(opts.auth_log, 'Image', 'succeeded', proof)
    298303    return extract_topo_from_message(resp_dict, opts.serialize_only)
    299304
     
    374379        top = get_experiment_topo(opts, cert, url)
    375380    except RPCException, e:
    376         exit_with_fault(e)
     381        exit_with_fault(e, 'image', opts)
    377382    except RuntimeError, e:
    378383        sys.exit("%s" % e)
     
    386391    except RPCException, e:
    387392        print >>sys.stderr, "Cannot extract a topology from %s" % opts.file
    388         exit_with_fault(e)
     393        exit_with_fault(e, 'image', opts)
    389394    except RuntimeError, e:
    390395        sys.exit("Cannot extract a topology from %s: %s" % (opts.file, e))
  • fedd/fedd_info.py

    r2627eb3 re83f2f2  
    33import sys
    44
     5from federation.proof import proof
    56from federation.remote_service import service_caller
    67from federation.client_lib import client_opts, exit_with_fault, RPCException,\
    7         wrangle_standard_options, do_rpc, get_experiment_names, info_format
     8        wrangle_standard_options, do_rpc, get_experiment_names, info_format, \
     9        log_authentication
    810
    911class exp_data_opts(client_opts):
     
    4345            caller=service_caller('Info'), responseBody='InfoResponseBody')
    4446except RPCException, e:
    45     exit_with_fault(e)
     47    exit_with_fault(e, 'Info', opts)
    4648except RuntimeError, e:
    4749    sys.exit("Error processing RPC: %s" % e)
     
    5355    except RuntimeError, e:
    5456        print >>sys.stderr, "Warning: %s" % e
     57proof = proof.from_dict(resp_dict.get('proof', {}))
     58if proof and opts.auth_log:
     59    log_authentication(opts.auth_log, 'Info', 'succeeded', proof)
  • fedd/fedd_multiinfo.py

    r2627eb3 re83f2f2  
    1010import time
    1111
     12from federation.proof import proof
    1213from federation.remote_service import service_caller
    1314from federation.client_lib import client_opts, exit_with_fault, RPCException,\
    14         wrangle_standard_options, do_rpc, info_format
     15        wrangle_standard_options, do_rpc, info_format, log_authentication
    1516
    1617class exp_data_opts(client_opts):
     
    3839            responseBody='MultiInfoResponseBody')
    3940except RPCException, e:
    40     exit_with_fault(e)
     41    exit_with_fault(e, 'MultiInfo', opts)
    4142except RuntimeError, e:
    4243    sys.exit("Error processing RPC: %s" % e)
     
    4748        formatter(i, d)
    4849    print "---"
     50proof = proof.from_dict(resp_dict.get('proof', {}))
     51if proof and opts.auth_log:
     52    log_authentication(opts.auth_log, 'MultiInfo', 'succeeded', proof)
  • fedd/fedd_multistatus.py

    r2627eb3 re83f2f2  
    33import sys
    44
     5from federation.proof import proof
    56from federation.remote_service import service_caller
    67from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    7         wrangle_standard_options, do_rpc, get_experiment_names
     8        wrangle_standard_options, do_rpc, get_experiment_names, \
     9        log_authentication
    810
    911parser = client_opts()
     
    2224            responseBody='MultiInfoResponseBody')
    2325except RPCException, e:
    24     exit_with_fault(e)
     26    exit_with_fault(e, 'MultiInfo', opts)
    2527except RuntimeError, e:
    2628    sys.exit("Error processing RPC: %s" % e)
     
    3335    print ":".join([ l or "" , "%s" % (f or "") ,
    3436        exp.get('experimentStatus', "") ])
     37proof = proof.from_dict(resp_dict.get('proof', {}))
     38if proof and opts.auth_log:
     39    log_authentication(opts.auth_log, 'MultiInfo', 'succeeded', proof)
  • fedd/fedd_new.py

    r2627eb3 re83f2f2  
    22
    33import sys
     4from datetime import datetime
    45
    56from federation.fedid import fedid, generate_fedid
    67from federation.remote_service import service_caller
     8from federation.proof import proof
    79from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    810        wrangle_standard_options, do_rpc, get_experiment_names, \
    9         save_certfile, get_abac_certs
    10 
     11        save_certfile, get_abac_certs, log_authentication
    1112
    1213class new_opts(client_opts):
     
    5859            caller=service_caller("New"), responseBody='NewResponseBody')
    5960except RPCException, e:
    60     exit_with_fault(e)
     61    exit_with_fault(e, 'New', opts)
    6162except RuntimeError, e:
    6263    sys.exit("Error processing RPC: %s" % e)
     
    7576e_fedid, e_local = get_experiment_names(resp_dict.get('experimentID', None))
    7677st = resp_dict.get('experimentStatus', None)
     78proof = proof.from_dict(resp_dict.get('proof', {}))
    7779
    7880if e_local: print "localname: %s" % e_local
    7981if e_fedid: print "fedid: %s" % e_fedid
    8082if st: print "status: %s" % st
     83if proof and opts.auth_log:
     84    log_authentication(opts.auth_log, 'New', 'succeeded', proof)
  • fedd/fedd_ns2topdl.py

    r2627eb3 re83f2f2  
    44
    55from federation import topdl
     6from federation.proof import proof
    67from federation.remote_service import service_caller
    78from federation.client_lib import client_opts, exit_with_fault, RPCException, \
     
    4546            responseBody="Ns2TopdlResponseBody")
    4647except RPCException, e:
    47     exit_with_fault(e)
     48    exit_with_fault(e, 'Ns2Topdl', opts)
    4849except RuntimeError, e:
    4950    sys.exit("Error processing RPC: %s" % e)
     
    6970else:
    7071    print topdl.topology_to_xml(top, top="experiment")
     72proof = proof.from_dict(resp_dict.get('proof', {}))
     73if proof and opts.auth_log:
     74    log_authentication(opts.auth_log, 'New (create)', 'succeeded', proof)
  • fedd/fedd_spewlog.py

    r2627eb3 re83f2f2  
    44import time
    55
     6from federation.proof import proof
    67from federation.remote_service import service_caller
    78from federation.client_lib import client_opts, exit_with_fault, RPCException, \
     
    6364                caller=service_caller('Info'), responseBody="InfoResponseBody")
    6465    except RPCException, e:
    65         exit_with_fault(e)
     66        exit_with_fault(e, 'Info (spewlog)', opts)
    6667    except RuntimeError, e:
    6768        sys.exit("Error processing RPC: %s" % e)
     69
     70    proof = proof.from_dict(resp_dict.get('proof', {}))
     71    if proof and opts.auth_log:
     72        log_authentication(opts.auth_log, 'Info (spewlog)', 'succeeded', proof)
    6873
    6974    if not opts.serialize_only:
  • fedd/fedd_terminate.py

    r2627eb3 re83f2f2  
    44
    55from federation.fedid import fedid
     6from federation.proof import proof
    67from federation.remote_service import service_caller
    78from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    8         wrangle_standard_options, do_rpc
     9        wrangle_standard_options, do_rpc, log_authentication
    910
    1011class terminate_opts(client_opts):
     
    6667            responseBody='TerminateResponseBody')
    6768except RPCException, e:
    68     exit_with_fault(e)
     69    exit_with_fault(e, 'Terminate', opts)
    6970except RuntimeError, e:
    7071    sys.exit("Error processing RPC: %s" % e)
     
    7879        out.close()
    7980        sys.exit("No log returned")
     81proof = proof.from_dict(resp_dict.get('proof', {}))
     82if proof and opts.auth_log:
     83    log_authentication(opts.auth_log, 'Terminate', 'succeeded', proof)
  • fedd/federation/access.py

    r2627eb3 re83f2f2  
    301301        # Check every attribute that we know how to map and take the first
    302302        # success.
     303        fail_proofs = [ ]
    303304        for attr in check:
    304             if self.auth.check_attribute(fid, attr.attr):
     305            access_ok, proof = self.auth.check_attribute(fid, attr.attr,
     306                    with_proof=True)
     307            if access_ok:
    305308                self.log.debug("Access succeeded for %s %s" % (attr.attr, fid))
    306309                # XXX: needs to deal with dynamics
    307310                return copy.copy(attr.value), (False, False, False), \
    308                         [ fid ]
     311                        [ fid ], proof
    309312            else:
     313                fail_proofs.append(proof)
    310314                self.log.debug("Access failed for %s %s" % (attr.attr, fid))
    311315        else:
    312             raise service_error(service_error.access, "Access denied")
     316            raise service_error(service_error.access, "Access denied",
     317                    proof=fail_proofs)
    313318
    314319
     
    448453        return (exp, state)
    449454
    450     def build_access_response(self, alloc_id, ap, services):
     455    def build_access_response(self, alloc_id, ap, services, proof):
    451456        """
    452457        Create the SOAP response.
     
    461466        msg = {
    462467                'allocID': alloc_id,
     468                'proof': proof.to_dict(),
    463469                'fedAttr': [
    464470                    { 'attribute': 'domain', 'value': self.domain } ,
     
    789795        # exception denying access that triggers a fault response back to the
    790796        # caller.
    791         found, match, owners = self.lookup_access(req, fid)
     797        found, match, owners, proof = self.lookup_access(req, fid)
    792798        self.log.info(
    793799                "[RequestAccess] Access granted to %s with local creds %s" % \
     
    819825                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
    820826        self.log.debug('[RequestAccess] Returning allocation ID: %s' % allocID)
    821         return { 'allocID': { 'fedid': allocID } }
     827        return { 'allocID': { 'fedid': allocID }, 'proof': proof.to_dict() }
    822828
    823829    def ReleaseAccess(self, req, fid):
     
    849855        self.log.debug("[ReleaseAccess] deallocation requested for %s", aid)
    850856        #  Confirm access
    851         if not self.auth.check_attribute(fid, auth_attr):
     857        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     858                with_proof=True)
     859        if not access_ok:
    852860            self.log.debug("[ReleaseAccess] deallocation denied for %s", aid)
    853             raise service_error(service_error.access, "Access Denied")
     861            raise service_error(service_error.access, "Access Denied",
     862                    proof=proof)
    854863
    855864        # If there is an allocation in the state, delete it.  Note the locking.
     
    865874            self.log.debug("[ReleaseAccess] Removing %s" % cf)
    866875            os.remove(cf)
    867             return { 'allocID': req['allocID'] }
     876            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    868877        else:
    869878            self.state_lock.release()
  • fedd/federation/authorizer.py

    r2627eb3 re83f2f2  
    11#/usr/local/bin/python
    22
    3 from string import join
    43from tempfile import mkstemp
    54from subprocess import call
     
    1211from service_error import service_error
    1312from util import abac_pem_type, abac_split_cert
     13from proof import proof
    1414
    1515
     
    116116        if attrs: attrs.discard(attr)
    117117
    118     def check_attribute(self, name, attr):
     118    def check_attribute(self, name, attr, with_proof=False):
    119119        """
    120120        Return True if name has attr (or if attr is global).  Tuple names match
     
    130130        self.valid_name(name)
    131131        if attr in self.globals:
    132             return True
     132            if with_proof: return True, proof("me", name, attr)
     133            else: return True
    133134
    134135        if isinstance(name, tuple):
     
    137138                if self.attrs.has_key(lookup):
    138139                    if attr in self.attrs[lookup]:
    139                         return True
    140         else:
    141             return  attr in self.attrs.get(self.auth_name(name), set())
     140                        if with_proof: return True, proof("me", name, attr)
     141                        else: return True
     142                # Drop through
     143                if with_proof: return False, proof("me", name, attr)
     144                else: return False
     145        else:
     146            if with_proof:
     147                return attr in self.attrs.get(self.auth_name(name), set()), \
     148                        proof("me", name, attr)
     149            else:
     150                return attr in self.attrs.get(self.auth_name(name), set())
    142151
    143152    def set_global_attribute(self, attr):
     
    375384
    376385
    377     def check_attribute(self, name, attr):
    378         # XXX proof soon
     386    def check_attribute(self, name, attr, with_proof=False):
    379387        if isinstance(name, tuple):
    380388            raise abac_authorizer.bad_name(
     
    399407            # Sigh. Unicode vs swig and swig seems to lose.  Make sure
    400408            # everything we pass into ABAC is a str not a unicode.
    401             rv, proof = self.context.query(a, n)
     409            rv, p = self.context.query(a, n)
    402410            # XXX delete soon
    403             if not rv and attr in self.globals: rv = True
    404             self.lock.release()
    405 
    406             return rv
     411            if not rv and attr in self.globals:
     412                rv = True
     413                p = None
     414            self.lock.release()
     415            if with_proof: return rv, proof(self.fedid, name, a, p)
     416            else: return rv
    407417
    408418    def set_global_attribute(self, attr):
  • fedd/federation/client_lib.py

    r2627eb3 re83f2f2  
    77
    88from string import join
     9from datetime import datetime
    910
    1011
     
    3132                callback=self.expand_file,
    3233                type="string", help="my certificate file")
     34        self.add_option("--auth_log", action="callback", dest="auth_log",
     35                callback=self.expand_file, default=None,
     36                type="string", help="Log authentication decisions to this file")
    3337        self.add_option("--abac", action="callback", dest="abac_dir",
    3438                callback=self.expand_file,
     
    5357                const=sys.stderr, help="Print SOAP exchange to stderr")
    5458
    55 def exit_with_fault(exc, out=sys.stderr):
     59def log_authentication(fn, action, outcome, proof):
     60    f = open(fn, 'a')
     61    print >>f, '%s %s at %s' % (action, outcome, datetime.now())
     62    if isinstance(proof, list):
     63        for p in proof:
     64            print >>f, p.to_xml()
     65    else:
     66        print >>f, proof.to_xml()
     67    f.close()
     68
     69
     70def exit_with_fault(exc, action, opts, out=sys.stderr):
    5671    """
    5772    Print an error message and exit.  exc is the RPCException that caused the
     
    7287        code = -1
    7388
     89    if exc.code == service_error.access and opts.auth_log:
     90        try:
     91            log_authentication(opts.auth_log, action, 'failed', exc.proof)
     92        except EnvironmentError, e:
     93            print >>sys.stderr, "Failed to log to %s: %s" % \
     94                    (e.filename, e.strerror)
     95
    7496    print>>out, codestr
    7597    print>>out, "Description: %s" % exc.desc
     
    81103    XMLPRC calls.
    82104    """
    83     def __init__(self, desc=None, code=None, errstr=None):
     105    def __init__(self, desc=None, code=None, errstr=None, proof=None):
    84106        RuntimeError.__init__(self)
    85107        self.desc = desc
     
    87109        else: self.code = -1
    88110        self.errstr = errstr
     111        self.proof = proof
    89112
    90113class CertificateMismatchError(RuntimeError): pass
     
    208231            except service_error, e:
    209232                raise RPCException(desc=e.desc, code=e.code,
    210                         errstr=e.code_string())
     233                        errstr=e.code_string(), proof=e.proof)
    211234    elif transport == "xmlrpc":
    212235        if serialize_only:
  • fedd/federation/deter_internal_access.py

    r2627eb3 re83f2f2  
    215215        aid = "%s" % auth_attr
    216216        attrs = req.get('fedAttr', [])
    217         if not self.auth.check_attribute(fid, auth_attr):
     217        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     218                with_proof=True)
     219        if not access_ok:
    218220            raise service_error(service_error.access, "Access denied")
    219221        else:
     
    271273                'allocID': req['allocID'],
    272274                'allocationLog': logv,
    273                 'segmentdescription': { 'topdldescription': rtopo.to_dict() }
     275                'segmentdescription': { 'topdldescription': rtopo.to_dict() },
     276                'proof': proof.to_dict(),
    274277                }
    275278        retval = copy.deepcopy(self.state[aid]['started'])
     
    289292
    290293        self.log.debug("Terminate request for %s" %aid)
    291         if not self.auth.check_attribute(fid, auth_attr):
     294        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     295                with_proof=True)
     296        if not access_ok:
    292297            raise service_error(service_error.access, "Access denied")
    293298
     
    308313        self.state[aid]['vlan'] = None
    309314        self.state_lock.release()
    310         return { 'allocID': req['allocID'] }
     315        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/dragon_access.py

    r2627eb3 re83f2f2  
    418418        return (repo, alloc_log)
    419419
    420     def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id):
     420    def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id, proof):
    421421        """
    422422        Place the relevant information in the global state block, and prepare
     
    442442                    'topdldescription': rtopo.to_dict()
    443443                    },
     444                'proof': proof.to_dict(),
    444445                }
    445446        retval = copy.deepcopy(self.state[aid]['started'])
     
    462463        aid = "%s" % auth_attr
    463464        attrs = req.get('fedAttr', [])
    464         if not self.auth.check_attribute(fid, auth_attr):
     465        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     466                with_proof=True)
     467        if not access_ok:
    465468            raise service_error(service_error.access, "Access denied")
    466469        else:
     
    508511        if gri:
    509512            return self.finalize_experiment(topo, vlan_no, gri, aid,
    510                     req['allocID'])
     513                    req['allocID'], proof)
    511514        elif err:
    512515            raise service_error(service_error.federant,
     
    526529        self.log.debug("Terminate request for %s" %aid)
    527530        attrs = req.get('fedAttr', [])
    528         if not self.auth.check_attribute(fid, auth_attr):
     531        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     532                with_proof=True)
     533        if not access_ok:
    529534            raise service_error(service_error.access, "Access denied")
    530535
     
    549554        self.log.debug("Stop segment for GRI: %s" %gri)
    550555        self.stop_segment(user, gri)
    551         return { 'allocID': req['allocID'] }
     556        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/emulab_access.py

    r2627eb3 re83f2f2  
    2424from service_error import service_error
    2525from remote_service import xmlrpc_handler, soap_handler, service_caller
     26from proof import proof as access_proof
    2627
    2728import httplib
     
    480481
    481482        if self.auth_type == "legacy":
    482             found, dyn, owners = self.legacy_lookup_access(req, fid)
     483            found, dyn, owners= self.legacy_lookup_access(req, fid)
     484            proof = access_proof("me", fid, "create")
    483485        elif self.auth_type == 'abac':
    484             found, dyn, owners = self.lookup_access(req, fid, filter=pf)
     486            found, dyn, owners, proof = self.lookup_access(req, fid, filter=pf)
    485487        else:
    486488            raise service_error(service_error.internal,
     
    523525                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
    524526        resp = self.build_access_response({ 'fedid': allocID } ,
    525                 ap, services)
     527                ap, services, proof)
    526528        return resp
    527529
     
    570572        self.log.debug("[access] deallocation requested for %s by %s" % \
    571573                (aid, fid))
    572         if not self.auth.check_attribute(fid, auth_attr):
     574        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     575                with_proof=True)
     576        if not access_ok:
    573577            self.log.debug("[access] deallocation denied for %s", aid)
    574578            raise service_error(service_error.access, "Access Denied")
     
    624628            self.log.debug("Removing %s" % cf)
    625629            os.remove(cf)
    626             return { 'allocID': req['allocID'] }
     630            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    627631        else:
    628632            self.state_lock.release()
     
    9971001        return (ename, proj, user, pubkey_base, secretkey_base, alloc_log)
    9981002
    999     def finalize_experiment(self, starter, topo, aid, alloc_id):
     1003    def finalize_experiment(self, starter, topo, aid, alloc_id, proof):
    10001004        """
    10011005        Store key bits of experiment state in the global repository, including
     
    10221026                    'topdldescription': topo.clone().to_dict()
    10231027                    },
    1024                 'embedding': embedding
     1028                'embedding': embedding,
     1029                'proof': proof.to_dict(),
    10251030                }
    10261031        retval = copy.copy(self.allocation[aid]['started'])
     
    10461051        aid = "%s" % auth_attr
    10471052        attrs = req.get('fedAttr', [])
    1048         if not self.auth.check_attribute(fid, auth_attr):
     1053
     1054        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     1055                with_proof=True)
     1056        if not access_ok:
    10491057            raise service_error(service_error.access, "Access denied")
    10501058        else:
     
    11121120
    11131121        if rv:
    1114             return self.finalize_experiment(starter, topo, aid, req['allocID'])
     1122            return self.finalize_experiment(starter, topo, aid, req['allocID'],
     1123                    proof)
    11151124        elif err:
    11161125            raise service_error(service_error.federant,
     
    11281137        aid = "%s" % auth_attr
    11291138        attrs = req.get('fedAttr', [])
    1130         if not self.auth.check_attribute(fid, auth_attr):
     1139
     1140        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     1141                with_proof=True)
     1142        if not access_ok:
    11311143            raise service_error(service_error.access, "Access denied")
    11321144
     
    11571169                debug=self.create_debug, boss=self.boss, cert=self.xmlrpc_cert)
    11581170        stopper(self, user, proj, ename)
    1159         return { 'allocID': req['allocID'] }
     1171        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/experiment_control.py

    r2627eb3 re83f2f2  
    801801            self.response = None
    802802            self.node = { }
     803            self.proof = None
    803804
    804805        def make_map(self, resp):
     
    850851                            self.log_collector.write(line)
    851852                    self.make_map(r['StartSegmentResponseBody'])
     853                    if 'proof' in r: self.proof = r['proof']
    852854                    self.response = r
    853855                else:
     
    10211023            # mapping.
    10221024            embedding = [ ]
     1025            proofs = { }
    10231026            for s in starters:
    10241027                for k, v in s.node.items():
     
    10281031                        'testbed': s.testbed
    10291032                        })
     1033                if s.proof:
     1034                    proofs[s.testbed] = s.proof
    10301035            log.info("[start_segment]: Experiment %s active" % eid)
    10311036
     
    10441049                top.to_dict()
    10451050        self.state[eid]['embedding'] = embedding
     1051        # Append startup proofs
     1052        for f in self.state[eid]['federant']:
     1053            if 'name' in f and 'localname' in f['name']:
     1054                if f['name']['localname'] in proofs:
     1055                    f['proof'].append(proofs[f['name']['localname']])
     1056
    10461057        if self.state_filename: self.write_state()
    10471058        self.state_lock.release()
     
    13261337            raise service_error(service_error.protocol,
    13271338                        "Bad proxy response")
     1339        if 'proof' not in r:
     1340            raise service_error(service_error.protocol,
     1341                        "Bad access response (no access proof)")
    13281342       
    13291343        tbparam[tb] = {
    13301344                "allocID" : r['allocID'],
    13311345                "uri": uri,
     1346                "proof": [ r['proof'] ],
    13321347                }
    13331348
     
    14981513            self.auth.save()
    14991514
    1500         if not self.auth.check_attribute(fid, 'new'):
    1501             raise service_error(service_error.access, "New access denied")
     1515        access_ok, proof = self.auth.check_attribute(fid, 'new',
     1516                with_proof=True)
     1517
     1518        if not access_ok:
     1519            raise service_error(service_error.access, "New access denied",
     1520                    proof=[proof])
    15021521
    15031522        try:
     
    15431562                ],
    15441563                'experimentStatus': 'empty',
    1545                 'experimentAccess': { 'X509' : expcert }
     1564                'experimentAccess': { 'X509' : expcert },
     1565                'proof': proof.to_dict(),
    15461566            }
    15471567
     
    18141834            raise service_error(service_error.req, "No request?")
    18151835
    1816         self.check_experiment_access(fid, key)
     1836        proof = self.check_experiment_access(fid, key)
    18171837
    18181838        self.state_lock.acquire()
    18191839        if self.state.has_key(key):
    18201840            if self.state[key].has_key('vtopo'):
    1821                 rv = { 'experiment' : {keytype: key },\
    1822                         'vtopo': self.state[key]['vtopo'],\
     1841                rv = { 'experiment' : {keytype: key },
     1842                        'vtopo': self.state[key]['vtopo'],
     1843                        'proof': proof.to_dict(),
    18231844                    }
    18241845            else:
     
    18581879            raise service_error(service_error.req, "No request?")
    18591880
    1860         self.check_experiment_access(fid, key)
     1881        proof = self.check_experiment_access(fid, key)
    18611882
    18621883        self.state_lock.acquire()
    18631884        if self.state.has_key(key):
    18641885            if self.state[key].has_key('vis'):
    1865                 rv =  { 'experiment' : {keytype: key },\
    1866                         'vis': self.state[key]['vis'],\
     1886                rv =  { 'experiment' : {keytype: key },
     1887                        'vis': self.state[key]['vis'],
     1888                        'proof': proof.to_dict(),
    18671889                        }
    18681890            else:
     
    18851907        between when it was started and the beginning of resource allocation.
    18861908        This is basically the information about each local allocation.  This
    1887         fills in the values of the placeholder allocation in the state.
     1909        fills in the values of the placeholder allocation in the state.  It
     1910        also collects the access proofs and returns them as dicts for a
     1911        response message.
    18881912        """
    18891913        # save federant information
     
    18931917                    'allocID' : tbparams[k]['allocID'],
    18941918                    'uri': tbparams[k]['uri'],
     1919                    'proof': tbparams[k]['proof'],
    18951920                }
    18961921
     
    19031928                [ tbparams[tb]['federant'] for tb in tbparams.keys() \
    19041929                    if tbparams[tb].has_key('federant') ]
     1930        # Access proofs for the response message
     1931        proofs = [copy.deepcopy(p) for k in tbparams.keys()\
     1932                    for p in tbparams[k]['federant']['proof']]
    19051933        if self.state_filename:
    19061934            self.write_state()
    19071935        self.state_lock.release()
     1936        return proofs
    19081937
    19091938    def clear_placeholder(self, eid, expid, tmpdir):
     
    19451974
    19461975        # Make sure that the caller can talk to us
    1947         self.check_experiment_access(fid, key)
     1976        proof = self.check_experiment_access(fid, key)
    19481977
    19491978        # Install the testbed map entries supplied with the request into a copy
     
    20302059            vtopo = topdl.topology_to_vtopo(top)
    20312060            vis = self.genviz(vtopo)
    2032             self.save_federant_information(allocated, tbparams, eid, vtopo,
    2033                     vis, top)
     2061            proofs = self.save_federant_information(allocated, tbparams,
     2062                    eid, vtopo, vis, top)
    20342063        except service_error, e:
    20352064            # If something goes wrong in the parse (usually an access error)
     
    20422071        # Start the background swapper and return the starting state.  From
    20432072        # here on out, the state will stick around a while.
    2044 
    2045         # XXX: I think this is redundant
    2046         # Let users touch the state
    2047         # self.auth.set_attribute(fid, expid)
    2048         # self.auth.set_attribute(expid, expid)
    2049         # Override fedids can manipulate state as well
    2050         # for o in self.overrides:
    2051             # self.auth.set_attribute(o, expid)
    2052         # self.auth.save()
    20532073
    20542074        # Create a logger that logs to the experiment's state object as well as
     
    20762096                ],
    20772097                'experimentStatus': 'starting',
     2098                'proof': [ proof.to_dict() ] + proofs,
    20782099            }
    20792100
     
    21212142            key = self.get_experiment_fedid(key)
    21222143
    2123         if self.auth.check_attribute(fid, key):
    2124             return True
     2144        access_ok, proof = self.auth.check_attribute(fid, key, with_proof=True)
     2145
     2146        if access_ok:
     2147            return proof
    21252148        else:
    2126             raise service_error(service_error.access, "Access Denied")
     2149            raise service_error(service_error.access, "Access Denied",
     2150                proof)
    21272151
    21282152
     
    21332157        """
    21342158        self.log.info("Get handler %s %s" % (path, fid))
     2159        # XXX: log proofs?
    21352160        if self.auth.check_attribute(fid, path):
    21362161            return ("%s/%s" % (self.repodir, path), "application/binary")
     
    21382163            return (None, None)
    21392164
    2140     def clean_info_response(self, rv):
     2165    def clean_info_response(self, rv, proof):
    21412166        """
    21422167        Remove the information in the experiment's state object that is not in
     
    21622187                if f.has_key('allocID'): del f['allocID']
    21632188                if f.has_key('uri'): del f['uri']
     2189        rv['proof'] = proof.to_dict()
    21642190
    21652191        return rv
     
    21882214            raise service_error(service_error.req, "No request?")
    21892215
    2190         self.check_experiment_access(fid, key)
     2216        proof = self.check_experiment_access(fid, key)
    21912217
    21922218        # The state may be massaged by the service function that called
     
    21992225
    22002226        if rv:
    2201             return self.clean_info_response(rv)
     2227            return self.clean_info_response(rv, proof)
    22022228        else:
    22032229            raise service_error(service_error.req, "No such experiment")
     
    22072233        Return all the stored info that this fedid can access
    22082234        """
    2209         rv = { 'info': [ ] }
     2235        rv = { 'info': [ ], 'proof': [ ] }
    22102236
    22112237        self.state_lock.acquire()
    22122238        for key in [ k for k in self.state.keys() if isinstance(k, fedid)]:
    22132239            try:
    2214                 self.check_experiment_access(fid, key)
     2240                proof = self.check_experiment_access(fid, key)
    22152241            except service_error, e:
    22162242                if e.code == service_error.access:
     
    22222248            if self.state.has_key(key):
    22232249                e = copy.deepcopy(self.state[key])
    2224                 e = self.clean_info_response(e)
     2250                e = self.clean_info_response(e, proof)
    22252251                rv['info'].append(e)
     2252                rv['proof'].append(proof.to_dict())
    22262253        self.state_lock.release()
    22272254        return rv
     
    23512378            if tmpdir: self.remove_dirs(tmpdir)
    23522379
    2353 
    23542380    def terminate_experiment(self, req, fid):
    23552381        """
     
    23642390
    23652391        key = self.get_experiment_key(req, 'experiment')
    2366         self.check_experiment_access(fid, key)
     2392        proof = self.check_experiment_access(fid, key)
    23672393        exp = req.get('experiment', False)
    23682394        force = req.get('force', False)
     
    24162442            if repo:
    24172443                self.remove_dirs("%s/%s" % (self.repodir, repo))
    2418                
     2444       
    24192445            return {
    24202446                    'experiment': exp ,
    24212447                    'deallocationLog': string.join(dealloc_list, ''),
     2448                    'proof': [proof.to_dict()],
    24222449                    }
    24232450        else:
     
    24382465        rv = { 'name': name }
    24392466
    2440         if name and self.auth.check_attribute(fid, name):
     2467        if not name:
     2468            raise service_error(service_error.req, "No name?")
     2469
     2470        access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True)
     2471
     2472        if access_ok:
    24412473            self.log.debug("[GetValue] asking for %s " % name)
    24422474            try:
     
    24482480            if v is not None:
    24492481                rv['value'] = v
     2482            rv['proof'] = proof.to_dict()
    24502483            self.log.debug("[GetValue] got %s from %s" % (v, name))
    24512484            return rv
    24522485        else:
    2453             raise service_error(service_error.access, "Access Denied")
     2486            raise service_error(service_error.access, "Access Denied",
     2487                    proof=proof)
    24542488       
    24552489
     
    24662500        v = req.get('value', '')
    24672501
    2468         if name and self.auth.check_attribute(fid, name):
     2502        if not name:
     2503            raise service_error(service_error.req, "No name?")
     2504
     2505        access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True)
     2506
     2507        if access_ok:
    24692508            try:
    24702509                self.synch_store.set_value(name, v)
     
    24792518                raise service_error(service_error.federant,
    24802519                        "Synch key %s revoked" % name)
    2481             return { 'name': name, 'value': v }
     2520                return { 'name': name, 'value': v, 'proof': proof.to_dict() }
    24822521        else:
    2483             raise service_error(service_error.access, "Access Denied")
     2522            raise service_error(service_error.access, "Access Denied",
     2523                    proof=proof)
  • fedd/federation/protogeni_access.py

    r2627eb3 re83f2f2  
    215215            return (None, None)
    216216
    217     def build_access_response(self, alloc_id, services):
     217    def build_access_response(self, alloc_id, services, proof):
    218218        """
    219219        Create the SOAP response.
     
    230230                'fedAttr': [
    231231                    { 'attribute': 'domain', 'value': self.domain } ,
    232                 ]
     232                ],
     233                'proof': proof.to_dict()
    233234            }
    234235        if self.dragon_endpoint:
     
    262263
    263264        # Request for this fedd
    264         found, match, owners = self.lookup_access(req, fid)
     265        found, match, owners, proof = self.lookup_access(req, fid)
    265266        services, svc_state = self.export_services(req.get('service',[]),
    266267                None, None)
     
    288289            raise service_error(service_error.internal,
    289290                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
    290         return self.build_access_response({ 'fedid': allocID }, None)
     291        return self.build_access_response({ 'fedid': allocID }, None, proof)
    291292
    292293
     
    312313
    313314        self.log.debug("[access] deallocation requested for %s", aid)
    314         if not self.auth.check_attribute(fid, auth_attr):
     315        access_ok , proof = self.auth.check_attribute(fid, auth_attr,
     316                with_proof=True)
     317        if not access_ok:
    315318            self.log.debug("[access] deallocation denied for %s", aid)
    316319            raise service_error(service_error.access, "Access Denied")
     
    327330            self.log.debug("Removing %s" % cf)
    328331            os.remove(cf)
    329             return { 'allocID': req['allocID'] }
     332            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    330333        else:
    331334            self.state_lock.release()
     
    12511254                cpw, alloc_log)
    12521255
    1253     def finalize_experiment(self, topo, nodes, aid, alloc_id):
     1256    def finalize_experiment(self, topo, nodes, aid, alloc_id, proof):
    12541257        # Copy the assigned names into the return topology
    12551258        rvtopo = topo.clone()
     
    12731276                    'topdldescription': rvtopo.to_dict() },
    12741277                'embedding': embedding,
     1278                'proof': proof.to_dict(),
    12751279                }
    12761280        retval = copy.deepcopy(self.allocation[aid]['started'])
     
    12951299        aid = "%s" % auth_attr
    12961300        attrs = req.get('fedAttr', [])
    1297         if not self.auth.check_attribute(fid, auth_attr):
     1301        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     1302                with_proof=True)
     1303        if not access_ok:
    12981304            raise service_error(service_error.access, "Access denied")
    12991305        else:
     
    13561362
    13571363        if rv:
    1358             return self.finalize_experiment(topo, nodes, aid, req['allocID'])
     1364            return self.finalize_experiment(topo, nodes, aid, req['allocID'],
     1365                    proof)
    13591366        elif err:
    13601367            raise service_error(service_error.federant,
     
    13921399        aid = "%s" % auth_attr
    13931400        attrs = req.get('fedAttr', [])
    1394         if not self.auth.check_attribute(fid, auth_attr):
     1401        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     1402                with_proof=True)
     1403        if not access_ok:
    13951404            raise service_error(service_error.access, "Access denied")
    13961405
     
    14191428        self.stop_segment(segment_commands, user, staging, slice_cred,
    14201429                slice_urn, cf, cpw)
    1421         return { 'allocID': req['allocID'] }
     1430        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    14221431
    14231432    def renew_segment(self, segment_commands, name, scred, slice_urn, interval,
  • fedd/federation/remote_service.py

    r2627eb3 re83f2f2  
    1616import httplib
    1717
     18from proof import proof
    1819from service_error import service_error
    1920from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary
     
    6667    # A map used to encapsulate fedids into xmlrpclib.Binary objects
    6768    encap_fedids = (('fedid', to_binary),)
     69
     70    # fields that are never unicoded, because they represent non strings.
     71    do_not_unicode = set(['credential'])
    6872
    6973    @staticmethod
     
    172176        if isinstance(obj, dict):
    173177            for k in obj.keys():
    174                 obj[k] = remote_service_base.make_unicode(obj[k])
     178                if k not in remote_service_base.do_not_unicode:
     179                    obj[k] = remote_service_base.make_unicode(obj[k])
    175180            return obj
    176181        elif isinstance(obj, basestring) and not isinstance(obj, unicode):
     
    513518                            'desc': e.fault.string or "Something Weird" }
    514519                if ee:
     520                    if 'proof' in ee:
     521                        pl = [ proof.from_dict(p) for p in ee['proof']]
     522                    else:
     523                        pl = None
    515524                    raise service_error(ee.get('code', 'no code'),
    516                             ee.get('desc','no desc'))
     525                            ee.get('desc','no desc'), proof=pl)
    517526                else:
    518527                    raise service_error(service_error.internal,
  • fedd/federation/server.py

    r2627eb3 re83f2f2  
    136136            self.send_fault(f)
    137137            resp = None
    138        
     138
    139139        if resp != None:
    140140            sw = SoapWriter()
     
    201201                de._errstr=e.code_string()
    202202                de._desc=e.desc
     203                for p in e.proof:
     204                    dp = ns0.proofType_Def(ns0.proofType_Def.schema,
     205                            "proof").pyclass()
     206                    dp._prover = p.prover
     207                    dp._principal = p.principal
     208                    dp._attribute = p.attribute
     209                    dp._credential = p.creds_to_certs()
     210                    if de._proof: de._proof.append(dp)
     211                    else: de._proof = [dp]
    203212                if  e.is_server_error():
    204213                    raise Fault(Fault.Server, e.code_string(), detail=de)
  • fedd/federation/service_error.py

    r2627eb3 re83f2f2  
    2828            federant, connect)
    2929
    30     def __init__(self, code=None, desc=None, from_string=None):
     30    def __init__(self, code=None, desc=None, from_string=None, proof=None):
    3131        self.code = code
    3232        self.desc = desc
     33        self.proof = proof or []
     34        if not isinstance (self.proof, list): self.proof = [ proof ]
    3335        if code == None:
    3436            self.set_code_from_string(from_string)
  • fedd/federation/skeleton_access.py

    r2627eb3 re83f2f2  
    183183        aid = "%s" % auth_attr
    184184        # Authorization check
    185         if not self.auth.check_attribute(fid, auth_attr):
    186             raise service_error(service_error.access, "Access denied")
     185        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     186                with_proof=True)
     187        if not access_ok:
     188            raise service_error(service_error.access, "Access denied",
     189                    proof=proof)
    187190        else:
    188191            # See if this is a replay of an earlier succeeded StartSegment -
     
    242245                'allocID': req['allocID'],
    243246                'allocationLog': "Allocatation complete",
    244                 'segmentdescription': { 'topdldescription': topo.to_dict() }
     247                'segmentdescription': { 'topdldescription': topo.to_dict() },
     248                'proof': proof.to_dict(),
    245249                }
    246250        retval = copy.deepcopy(self.state[aid]['started'])
     
    266270        self.log.debug("Terminate request for %s" %aid)
    267271        # Check authorization
    268         if not self.auth.check_attribute(fid, auth_attr):
    269             raise service_error(service_error.access, "Access denied")
     272        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     273                with_proof=True)
     274        if not access_ok:
     275            raise service_error(service_error.access, "Access denied",
     276                    proof=proof)
    270277
    271278        # Authorized: remove the integer from the allocation.  A more complex
     
    281288        self.state_lock.release()
    282289   
    283         return { 'allocID': req['allocID'] }
     290        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/thread_pool.py

    r2627eb3 re83f2f2  
    44import time
    55from threading import Lock, Thread, Condition
     6from service_error import service_error
    67
    78class thread_pool:
  • wsdl/fedd_types.xsd

    r2627eb3 re83f2f2  
    131131
    132132  <!-- end deprecated -->
     133
     134  <xsd:complexType name="proofType">
     135    <xsd:annotation>
     136      <xsd:documentation>
     137        A proof or partial proof of access rights
     138      </xsd:documentation>
     139    </xsd:annotation>
     140    <xsd:sequence>
     141      <xsd:element name="prover" type="xsd:string"/>
     142      <xsd:element name="principal" type="xsd:string"/>
     143      <xsd:element name="attribute" type="xsd:string"/>
     144      <xsd:element name="credential" type="xsd:base64Binary"
     145        maxOccurs="unbounded" minOccurs="0"/>
     146    </xsd:sequence>
     147  </xsd:complexType>
    133148
    134149  <xsd:simpleType name="statusType">
     
    478493      <xsd:element name="experimentStatus" type="tns:statusType"/>
    479494      <xsd:element name="experimentAccess" type="tns:accessType"/>
     495      <xsd:element name="proof" type="tns:proofType"/>
    480496    </xsd:sequence>
    481497  </xsd:complexType>
     
    523539      <xsd:element name="fedAttr" type="tns:fedAttrType" minOccurs="0"
    524540        maxOccurs="unbounded"/>
     541      <xsd:element name="proof" type="tns:proofType"/>
    525542    </xsd:sequence>
    526543  </xsd:complexType>
     
    546563    <xsd:sequence>
    547564      <xsd:element name="allocID" type="tns:IDType"/>
     565      <xsd:element name="proof" type="tns:proofType"/>
    548566    </xsd:sequence>
    549567  </xsd:complexType>
     
    584602        maxOccurs="unbounded"/>
    585603      <xsd:element name="experimentStatus" type="tns:statusType"/>
     604      <xsd:element name="proof" type="tns:proofType" minOccurs="1"
     605        maxOccurs="unbounded"/>
    586606    </xsd:sequence>
    587607  </xsd:complexType>
     
    610630      <xsd:element name="experiment" type="tns:IDType"/>
    611631      <xsd:element name="vtopo" type="tns:vtopoType"/>
     632      <xsd:element name="proof" type="tns:proofType"/>
    612633    </xsd:sequence>
    613634  </xsd:complexType>
     
    638659      <xsd:element name="experiment" type="tns:IDType"/>
    639660      <xsd:element name="vis" type="tns:visType"/>
     661      <xsd:element name="proof" type="tns:proofType"/>
    640662    </xsd:sequence>
    641663  </xsd:complexType>
     
    666688    <xsd:sequence>
    667689      <xsd:element name="name" type="tns:IDType" minOccurs="1"
     690        maxOccurs="unbounded"/>
     691      <xsd:element name="proof" type="tns:proofType" minOccurs="1"
    668692        maxOccurs="unbounded"/>
    669693    </xsd:sequence>
     
    719743      <xsd:element name="embedding" type="tns:embeddingMapType" minOccurs="0"
    720744        maxOccurs="unbounded"/>
     745      <xsd:element name="proof" type="tns:proofType"/>
    721746    </xsd:sequence>
    722747  </xsd:complexType>
     
    741766    <xsd:sequence>
    742767      <xsd:element name="info" type="tns:infoResponseType" minOccurs="0"
     768        maxOccurs="unbounded"/>
     769      <xsd:element name="proof" type="tns:proofType" minOccurs="0"
    743770        maxOccurs="unbounded"/>
    744771    </xsd:sequence>
     
    767794      <xsd:element name="deallocationLog" type="xsd:string" minOccurs="0"
    768795        maxOccurs="1"/>
     796      <xsd:element name="proof" type="tns:proofType" minOccurs="1" maxOccurs="unbounded"/>
    769797    </xsd:sequence>
    770798  </xsd:complexType>
     
    805833      <xsd:element name="fedAttr" type="tns:fedAttrType" minOccurs="0"
    806834        maxOccurs="unbounded"/>
     835      <xsd:element name="proof" type="tns:proofType" />
    807836    </xsd:sequence>
    808837  </xsd:complexType>
     
    830859      <xsd:element name="deallocationLog" type="xsd:string" minOccurs="0"
    831860        maxOccurs="1"/>
     861      <xsd:element name="proof" type="tns:proofType" />
    832862    </xsd:sequence>
    833863  </xsd:complexType>
     
    854884      <xsd:element name="experimentdescription"
    855885        type="tns:experimentDescriptionType"/>
     886      <xsd:element name="proof" type="tns:proofType"/>
    856887    </xsd:sequence>
    857888  </xsd:complexType>
     
    878909      <xsd:element name="name" type="xsd:string"/>
    879910      <xsd:element name="value" type="xsd:string"/>
     911      <xsd:element name="proof" type="tns:proofType"/>
    880912    </xsd:sequence>
    881913  </xsd:complexType>
     
    902934      <xsd:element name="name" type="xsd:string"/>
    903935      <xsd:element name="value" type="xsd:string" minOccurs="0" maxOccurs="1"/>
     936      <xsd:element name="proof" type="tns:proofType"/>
    904937    </xsd:sequence>
    905938  </xsd:complexType>
     
    939972      </xsd:element>
    940973      <xsd:element name="desc" type="xsd:string"/>
     974      <xsd:element name="proof" type="tns:proofType"
     975        minOccurs="0" maxOccurs="unbounded"/>
    941976    </xsd:sequence>
    942977  </xsd:complexType>
Note: See TracChangeset for help on using the changeset viewer.