Changeset 0a49bd7


Ignore:
Timestamp:
Jan 15, 2011 5:52:15 PM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
aaf7f41
Parents:
ac15159 (diff), 944b746 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Ted Faber <faber@…> (01/15/11 17:51:40)
git-committer:
Ted Faber <faber@…> (01/15/11 17:52:15)
Message:

merge from current

Files:
2 added
36 edited

Legend:

Unmodified
Added
Removed
  • fedd/Makefile

    rac15159 r0a49bd7  
    44GENERATED_MODS= ${MODULE_DIR}/fedd_services.py \
    55                ${MODULE_DIR}/fedd_internal_services.py \
    6                 ${MODULE_DIR}/fedd_services_types.py
     6                ${MODULE_DIR}/fedd_internal_services_types.py \
     7                ${MODULE_DIR}/fedd_client.py \
     8                ${MODULE_DIR}/fedd_internal_client.py \
     9                ${MODULE_DIR}/fedd_internal_server.py \
     10                ${MODULE_DIR}/fedd_internal_types.py \
     11                ${MODULE_DIR}/fedd_types.py \
     12                ${MODULE_DIR}/fedd_server.py
     13
    714WSDL_FILES= ../wsdl/fedd.wsdl ../wsdl/fedd_types.xsd ../wsdl/fedd_internal.wsdl ../wsdl/topdl.xsd
    815
    9 VERSION=3.01
     16VERSION=3.20
    1017
    1118DISTFILES= dist/fedd-${VERSION}.tar.gz
     
    1522
    1623${GENERATED_MODS}:      ${WSDL_FILES}
    17         wsdl2py --complexType --output-dir=${MODULE_DIR} ../wsdl/fedd.wsdl
    18         wsdl2py --complexType --output-dir=${MODULE_DIR} ../wsdl/fedd_internal.wsdl
     24        python ./compile_wsdl.py --complexType --output-dir=${MODULE_DIR} ../wsdl/fedd.wsdl
     25        python ./compile_wsdl.py --complexType --output-dir=${MODULE_DIR} ../wsdl/fedd_internal.wsdl
    1926
    2027clean:
  • fedd/access_to_abac.py

    rac15159 r0a49bd7  
    1212from federation.fedid import fedid
    1313from federation.authorizer import abac_authorizer
    14 from federation.util import abac_split_cert, abac_pem_type
     14from federation.util import abac_split_cert, abac_pem_type, file_expanding_opts
    1515
    1616
     
    185185
    186186
    187 def parse_access(fn, mapper):
     187def parse_access(fn, mapper, delegation_link):
    188188    """
    189189    Parse the access file, calling out to the mapper to parse specific
     
    224224
    225225
    226 class access_opts(OptionParser):
     226class access_opts(file_expanding_opts):
    227227    '''
    228228    Parse the options for this program.  Most are straightforward, but the
     
    247247
    248248    def __init__(self):
    249         OptionParser.__init__(self, usage='%prog [opts] file [...]')
     249        file_expanding_opts.__init__(self, usage='%prog [opts] file [...]')
    250250        self.add_option('--cert', dest='cert', default=None,
     251                type='str', action='callback', callback=self.expand_file,
    251252                help='my fedid as an X.509 certificate')
    252253        self.add_option('--key', dest='key', default=None,
     254                type='str', action='callback', callback=self.expand_file,
    253255                help='key for the certificate')
    254256        self.add_option('--dir', dest='dir', default=None,
     257                type='str', action='callback', callback=self.expand_file,
    255258                help='Output directory for credentials')
    256259        self.add_option('--type', action='callback', nargs=1, type='str',
     
    263266                default=False,
    264267                help='Do not print credential to local attribute map')
    265         self.add_option('--create-creds', action='store_true',
    266                 dest='create_creds', default=False,
    267                 help='create credentials for rules.  Requires ' + \
    268                         '--cert, --key, and --dir to be given.')
     268        self.add_option('--no_create_creds', action='store_false',
     269                dest='create_creds', default=True,
     270                help='Do not create credentials for rules.')
    269271        self.add_option('--file', dest='file', default=None,
     272                type='str', action='callback', callback=self.expand_file,
    270273                help='Access DB to parse.  If this is present, ' + \
    271274                        'omit the positional filename')
    272275        self.add_option('--mapfile', dest='map', default=None,
     276                type='str', action='callback', callback=self.expand_file,
    273277                help='File for the attribute to local authorization data')
    274278        self.add_option('--no-delegate', action='store_false', dest='delegate',
     
    276280                help='do not accept delegated attributes with the ' +\
    277281                        'acting_for linking role')
    278         self.add_option('--auth', action='store_true', dest='create_auth',
    279                 default=False, help='create a full ABAC authorizer')
     282        self.add_option('--no_auth', action='store_false', dest='create_auth',
     283                default=True, help='do not create a full ABAC authorizer')
    280284        self.add_option('--debug', action='store_true', dest='debug',
    281285                default=False, help='Just print actions')
     
    402406    for fn in args:
    403407        try:
    404             creds, to_id = parse_access(fn, opts.mapper)
     408            creds, to_id = parse_access(fn, opts.mapper, delegation_link)
    405409        except parse_error, e:
    406410            print >> sys.stderr, "%s" % e
  • fedd/cert_to_fedid.py

    rac15159 r0a49bd7  
    33import sys, os
    44import subprocess, tempfile
     5import os.path
     6import re
     7
     8from M2Crypto import X509
    59
    610from string import join
    7 from optparse import OptionParser
    8 from federation.util import abac_pem_type, abac_split_cert
     11from federation.util import abac_pem_type, abac_split_cert, file_expanding_opts
    912
    10 class Parser(OptionParser):
     13class Parser(file_expanding_opts):
    1114    def __init__(self):
    12         OptionParser.__init__(self, usage='%prog [options]')
     15        file_expanding_opts.__init__(self, usage='%prog [options]')
    1316        self.add_option('--out', dest='out', help='destination file',
     17                action='callback', callback=self.expand_file, type='str',
    1418                default='./cert.pem')
    1519        self.add_option('--debug', dest='debug', action='store_true',
    1620                default=False, help='Just print command')
     21        self.add_option('--cert', dest='cert',
     22                help='Cretificate to copy subject from')
    1723        self.add_option('--openssl', dest='openssl',
    1824                help='Path to openssl command', default='/usr/bin/openssl')
     
    3137    delete_key = True
    3238elif ktype != 'key':
    33     sys.exit('Cannot use %s as identity.  It is a %s ' % ktype +
     39    sys.exit('Cannot use %s as identity.  It is a %s ' % (key, ktype) +
    3440        'and we were expecting a key')
    3541
    3642
    3743try:
     44    c = X509.load_cert(opts.cert)
     45    subj = c.get_subject().as_text()
     46    if subj.startswith('/'): i = 1
     47    else: i = 0
     48    subj = '/' + re.sub('/', '\/', subj[i:])
     49
    3850    tf, tn = tempfile.mkstemp(suffix=".pem")
    3951    cmd = [opts.openssl, 'req', '-new', '-nodes', '-subj',
    40             '/CN=users.isi.deterlab.net', '-x509', '-days',  '3650',
     52            subj, '-x509', '-days',  '3650',
    4153            '-key', key, '-out', tn]
    4254    if opts.debug:
  • fedd/confirm_sshkey.py

    rac15159 r0a49bd7  
    33import os, sys
    44import MySQLdb
    5 from optparse import OptionParser
     5from federation.util import file_expanding_opts
    66
    77
    8 class opt_parser(OptionParser):
     8class opt_parser(file_expanding_opts):
    99    def __init__(self):
    1010        OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
     
    1212        self.add_option('-u', '--user', dest='user', action='store',
    1313                default=None, help="User to confirm key of")
    14         self.add_option('-f', '--keyfile', dest='keyfile', action='store',
     14        self.add_option('-f', '--keyfile', dest='keyfile',
     15                action='callback', callback=self.expand_file, type='str',
    1516                default=None, help="file containing pubkey to confirm")
    16         self.add_option('-k', '--key', dest='key',
    17                 default=None, action='store',
     17        self.add_option('-k', '--key', dest='key', default=None,
     18                action='callback', callback=self.expand_file, type='str',
    1819                help='Key on the command line')
    1920        self.add_option('-q', '--quiet', dest='verbose', action='store_false',
  • fedd/creddy_split.py

    rac15159 r0a49bd7  
    55import os
    66
    7 from optparse import OptionParser
    8 from federation.util import abac_split_cert, abac_pem_type
     7from federation.util import abac_split_cert, abac_pem_type, file_expanding_opts
    98
    109# Options
    11 class Parser(OptionParser):
     10class Parser(file_expanding_opts):
    1211    def __init__(self):
    13         OptionParser.__init__(self, usage="%prog [options] file.pem")
     12        file_expanding_opts.__init__(self, usage="%prog [options] file.pem")
    1413        self.add_option('--cert', dest='cert', default='./cert.pem',
     14                action='callback', callback=self.expand_file, type='str',
    1515                help='File to extract certificate into, default: [%default]')
    1616        self.add_option('--key', dest='key', default='./key.pem',
     17                action='callback', callback=self.expand_file, type='str',
    1718                help='File to extract key into, default: [%default]')
    1819        self.add_option('--force', action='store_true', dest='force',
  • fedd/fedd.py

    rac15159 r0a49bd7  
    77from federation import config_parser
    88from federation.server import server, xmlrpc_handler, soap_handler
    9 from federation.util import fedd_ssl_context
     9from federation.util import fedd_ssl_context, file_expanding_opts
    1010from federation.deter_impl import new_feddservice
    1111
     
    1818import logging
    1919import M2Crypto
    20 
    21 class fedd_opts(OptionParser):
     20import os.path
     21
     22class fedd_opts(file_expanding_opts):
    2223    """Encapsulate option processing in this class, rather than in main"""
     24
    2325    def __init__(self):
    24         OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
     26        file_expanding_opts.__init__(self,
     27                usage="%prog [opts] (--help for details)",
    2528                version="0.1")
    2629
     
    2932        self.add_option("-d", "--debug", action="count", dest="debug",
    3033                help="Set debug.  Repeat for more information")
    31         self.add_option("-f", "--configfile", action="store",
     34        self.add_option("-f", "--configfile", action="callback",
     35                callback=self.expand_file, type='str',
    3236                default="/usr/local/etc/fedd.conf",
    33                 dest="configfile", help="Configuration file (required)")
     37                dest="configfile", help="Configuration file")
    3438        self.add_option("-l", "--logfile", action="store", dest="logfile",
    3539                help="File to send log messages to")
  • fedd/fedd_create.py

    rac15159 r0a49bd7  
    77import ABAC
    88
    9 from string import join
    10 
     9from string import join, ascii_letters
     10from random import choice
     11
     12from federation.proof import proof
    1113from federation.fedid import fedid, generate_fedid
    1214from federation.remote_service import service_caller
    1315from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    1416        wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,\
    15         get_abac_certs
     17        get_abac_certs, log_authentication
    1618from federation.util import abac_split_cert, abac_context_to_creds
    1719from federation import topdl
     
    2628        client_opts.__init__(self)
    2729        self.add_option("--experiment_cert", dest="out_certfile",
     30                action="callback", callback=self.expand_file,
    2831                type="string", help="output certificate file")
    2932        self.add_option("--experiment_name", dest="exp_name",
    3033                type="string", help="Suggested experiment name")
    31         self.add_option("--file", dest="file",
     34        self.add_option("--file", dest="file", action="callback",
     35                callback=self.expand_file, type="str",
    3236                help="experiment description file")
    3337        self.add_option("--project", action="store", dest="project",
     
    153157(opts, args) = parser.parse_args()
    154158
     159svcs = []
    155160# Option processing
    156 cert, fid, url = wrangle_standard_options(opts)
     161try:
     162    cert, fid, url = wrangle_standard_options(opts)
     163except RuntimeError, e:
     164    sys.exit("%s" %e)
    157165
    158166if opts.file:
     
    199207
    200208# Fill in services
    201 svcs = []
    202209if opts.master and opts.project:
    203210    svcs.append(project_export_service(opts.master, opts.project))
     
    231238if acerts:
    232239    msg['credential'] = acerts
     240
     241# ZSI will not properly construct an empty message.  If nothing has been added
     242# to msg, pick a random localname to ensure the message is created
     243if not msg:
     244    msg['experimentID'] = {
     245            'localname': join([choice(ascii_letters) for i in range(0,8)],""),
     246            }
     247
    233248
    234249if opts.debug > 1: print >>sys.stderr, msg
     
    242257            caller=service_caller('New'), responseBody="NewResponseBody")
    243258except RPCException, e:
    244     exit_with_fault(e)
     259    exit_with_fault(e, 'New (create)', opts)
    245260except RuntimeError, e:
    246261    sys.exit("Error processing RPC: %s" % e)
     
    248263if opts.debug > 1: print >>sys.stderr, resp_dict
    249264
     265proof = proof.from_dict(resp_dict.get('proof', {}))
     266if proof and opts.auth_log:
     267    log_authentication(opts.auth_log, 'New (create)', 'succeeded', proof)
    250268# Save the experiment ID certificate if we need it
    251269try:
     
    298316            serialize_only=opts.serialize_only,
    299317            tracefile=opts.tracefile,
    300             caller=service_caller('Create'), responseBody="CreateResponseBody")
     318            caller=service_caller('Create', max_retries=1), responseBody="CreateResponseBody")
    301319except RPCException, e:
    302     exit_with_fault(e)
     320    exit_with_fault(e, 'Create', opts)
    303321except RuntimeError, e:
    304322    sys.exit("Error processing RPC: %s" % e)
     
    313331if e_fedid: print "fedid: %s" % e_fedid
    314332if st: print "status: %s" % st
    315 
     333proof = proof.from_dict(resp_dict.get('proof', {}))
     334if proof and opts.auth_log:
     335    log_authentication(opts.auth_log, 'Create', 'succeeded', proof)
  • fedd/fedd_ftopo.py

    rac15159 r0a49bd7  
    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):
     
    1214        client_opts.__init__(self)
    1315        self.add_option("--experiment_cert", dest="exp_certfile",
    14                 type="string", help="experiment certificate file")
     16                action='callback', callback=self.expand_file, type='str',
     17                help="experiment certificate file")
    1518        self.add_option("--experiment_name", dest="exp_name",
    1619                type="string", help="human readable experiment name")
     
    4144            caller=service_caller('Info'), responseBody='InfoResponseBody')
    4245except RPCException, e:
    43     exit_with_fault(e)
     46    exit_with_fault(e, 'Ftopo', opts)
    4447except RuntimeError, e:
    4548    sys.exit("Error processing RPC: %s" % e)
     
    6467else:
    6568    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

    rac15159 r0a49bd7  
    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
     
    1719        client_opts.__init__(self)
    1820        self.add_option("--experiment_cert", dest="exp_certfile",
    19                 type="string", help="experiment certificate file")
     21                action='callback', callback=self.expand_file, type='str',
     22                help="experiment certificate file")
    2023        self.add_option("--experiment_name", dest="exp_name",
    2124                type="string", help="human readable experiment name")
    22         self.add_option("--output", dest="outfile", type="string",
     25        self.add_option("--output", dest="outfile",
     26                action='callback', callback=self.expand_file, type='str',
    2327                help="output image file")
    2428        self.add_option("--format", dest="format", type="choice",
     
    3842                help="Size of output in pixels (diagrams are square")
    3943        self.add_option("--file", dest="file",
     44                action='callback', callback=self.expand_file, type='str',
    4045                help="experiment description file")
    4146        self.add_option("--group", dest="group", action="append", default=[],
     
    293298            caller=service_caller('Info'), responseBody="InfoResponseBody")
    294299
     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)
    295303    return extract_topo_from_message(resp_dict, opts.serialize_only)
    296304
     
    333341(opts, args) = parser.parse_args()
    334342
    335 # Note that if we're converting a local topdl file, the absence of a cert may
    336 # not be a big deal.  It's checked if needed below
     343# Note that if we're converting a local topdl file, the absence of a cert or
     344# abac directory may not be a big deal.  It's checked if needed below
    337345try:
    338346    cert, fid, url = wrangle_standard_options(opts)
    339347except RuntimeError, e:
    340348    cert = None
    341     print >>sys.stderr, "Warning: %s e"
     349    print >>sys.stderr, "Warning: %s" % e
    342350
    343351
     
    371379        top = get_experiment_topo(opts, cert, url)
    372380    except RPCException, e:
    373         exit_with_fault(e)
     381        exit_with_fault(e, 'image', opts)
    374382    except RuntimeError, e:
    375383        sys.exit("%s" % e)
     
    383391    except RPCException, e:
    384392        print >>sys.stderr, "Cannot extract a topology from %s" % opts.file
    385         exit_with_fault(e)
     393        exit_with_fault(e, 'image', opts)
    386394    except RuntimeError, e:
    387395        sys.exit("Cannot extract a topology from %s: %s" % (opts.file, e))
  • fedd/fedd_info.py

    rac15159 r0a49bd7  
    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):
     
    1113        client_opts.__init__(self)
    1214        self.add_option("--experiment_cert", dest="exp_certfile",
    13                 type="string", help="experiment certificate file")
     15                action='callback', callback=self.expand_file, type='str',
     16                help="experiment certificate file")
    1417        self.add_option("--experiment_name", dest="exp_name",
    1518                type="string", help="human readable experiment name")
     
    4245            caller=service_caller('Info'), responseBody='InfoResponseBody')
    4346except RPCException, e:
    44     exit_with_fault(e)
     47    exit_with_fault(e, 'Info', opts)
    4548except RuntimeError, e:
    4649    sys.exit("Error processing RPC: %s" % e)
     
    5255    except RuntimeError, e:
    5356        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

    rac15159 r0a49bd7  
    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):
     
    2526parser = exp_data_opts()
    2627(opts, args) = parser.parse_args()
    27 cert, fid, url = wrangle_standard_options(opts)
     28try:
     29    cert, fid, url = wrangle_standard_options(opts)
     30except RuntimeError, e:
     31    sys.exit("%s" %e)
    2832
    2933try:
     
    3539            responseBody='MultiInfoResponseBody')
    3640except RPCException, e:
    37     exit_with_fault(e)
     41    exit_with_fault(e, 'MultiInfo', opts)
    3842except RuntimeError, e:
    3943    sys.exit("Error processing RPC: %s" % e)
     
    4448        formatter(i, d)
    4549    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

    rac15159 r0a49bd7  
    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()
    1012(opts, args) = parser.parse_args()
    11 cert, fid, url = wrangle_standard_options(opts)
     13try:
     14    cert, fid, url = wrangle_standard_options(opts)
     15except RuntimeError, e:
     16    sys.exit("%s" %e)
    1217
    1318try:
     
    1924            responseBody='MultiInfoResponseBody')
    2025except RPCException, e:
    21     exit_with_fault(e)
     26    exit_with_fault(e, 'MultiInfo', opts)
    2227except RuntimeError, e:
    2328    sys.exit("Error processing RPC: %s" % e)
     
    3035    print ":".join([ l or "" , "%s" % (f or "") ,
    3136        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

    rac15159 r0a49bd7  
    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):
     
    1415        client_opts.__init__(self)
    1516        self.add_option("--experiment_cert", dest="out_certfile",
    16                 type="string", help="output certificate file")
     17                action='callback', callback=self.expand_file, type='str',
     18                help="output certificate file")
    1719        self.add_option("--experiment_name", dest="exp_name",
    1820                type="string", help="Suggested experiment name")
     
    2426(opts, args) = parser.parse_args()
    2527
    26 cert, fid, url = wrangle_standard_options(opts)
    2728try:
     29    cert, fid, url = wrangle_standard_options(opts)
    2830    acerts = get_abac_certs(opts.abac_dir)
    2931except EnvironmentError, e:
    3032    sys.exit('%s: %s' % (e.filename, e.strerror))
     33except RuntimeError, e:
     34    sys.exit("%s" %e)
    3135
    3236out_certfile = opts.out_certfile
     
    5559            caller=service_caller("New"), responseBody='NewResponseBody')
    5660except RPCException, e:
    57     exit_with_fault(e)
     61    exit_with_fault(e, 'New', opts)
    5862except RuntimeError, e:
    5963    sys.exit("Error processing RPC: %s" % e)
     
    7276e_fedid, e_local = get_experiment_names(resp_dict.get('experimentID', None))
    7377st = resp_dict.get('experimentStatus', None)
     78proof = proof.from_dict(resp_dict.get('proof', {}))
    7479
    7580if e_local: print "localname: %s" % e_local
    7681if e_fedid: print "fedid: %s" % e_fedid
    7782if st: print "status: %s" % st
     83if proof and opts.auth_log:
     84    log_authentication(opts.auth_log, 'New', 'succeeded', proof)
  • fedd/fedd_ns2topdl.py

    rac15159 r0a49bd7  
    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, \
     
    1213        client_opts.__init__(self)
    1314        self.add_option("--file", dest="file",
     15                action='callback', callback=self.expand_file, type='str',
    1416                help="experiment description file")
    1517        self.add_option("--output", dest="outfile", type="string",
     
    1921(opts, args) = parser.parse_args()
    2022
    21 cert, fid, url = wrangle_standard_options(opts)
     23try:
     24    cert, fid, url = wrangle_standard_options(opts)
     25except RuntimeError, e:
     26    sys.exit("%s" %e)
    2227
    2328if opts.file:
     
    4146            responseBody="Ns2TopdlResponseBody")
    4247except RPCException, e:
    43     exit_with_fault(e)
     48    exit_with_fault(e, 'Ns2Topdl', opts)
    4449except RuntimeError, e:
    4550    sys.exit("Error processing RPC: %s" % e)
     
    6570else:
    6671    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

    rac15159 r0a49bd7  
    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, \
     
    1213        client_opts.__init__(self)
    1314        self.add_option("--experiment_cert", dest="exp_certfile",
    14                 type="string", help="experiment name certificate file")
     15                action='callback', callback=self.expand_file, type='str',
     16                help="experiment name certificate file")
    1517        self.add_option("--experiment_name", dest="exp_name",
    1618                type="string", help="human readable experiment name")
    1719        self.add_option("--logfile", dest="logfile", default=None,
     20                action='callback', callback=self.expand_file, type='str',
    1821                help="File to write log to")
    1922        self.add_option('--update_time', dest='update', type='int', default=10,
     
    2528(opts, args) = parser.parse_args()
    2629
    27 cert, fid, url = wrangle_standard_options(opts)
     30try:
     31    cert, fid, url = wrangle_standard_options(opts)
     32except RuntimeError, e:
     33    sys.exit("%s" %e)
    2834
    2935if opts.exp_name and opts.exp_certfile:
     
    5864                caller=service_caller('Info'), responseBody="InfoResponseBody")
    5965    except RPCException, e:
    60         exit_with_fault(e)
     66        exit_with_fault(e, 'Info (spewlog)', opts)
    6167    except RuntimeError, e:
    6268        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)
    6373
    6474    if not opts.serialize_only:
  • fedd/fedd_terminate.py

    rac15159 r0a49bd7  
    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):
     
    1213        client_opts.__init__(self)
    1314        self.add_option("--experiment_cert", dest="exp_certfile",
    14                 type="string", help="experiment certificate file")
     15                action='callback', callback=self.expand_file, type='str',
     16                help="experiment certificate file")
    1517        self.add_option("--experiment_name", dest="exp_name",
    1618                type="string", help="human readable experiment name")
     
    1921                help="Force termination if experiment is in strange state")
    2022        self.add_option("--logfile", dest="logfile", default=None,
     23                action='callback', callback=self.expand_file, type='str',
    2124                help="File to write log to")
    2225        self.add_option("--print_log", dest="print_log", default=False,
     
    2730parser = terminate_opts()
    2831(opts, args) = parser.parse_args()
    29 cert, fid, url = wrangle_standard_options(opts)
     32
     33try:
     34    cert, fid, url = wrangle_standard_options(opts)
     35except RuntimeError, e:
     36    sys.exit("%s" %e)
    3037
    3138if opts.exp_name and opts.exp_certfile:
     
    6067            responseBody='TerminateResponseBody')
    6168except RPCException, e:
    62     exit_with_fault(e)
     69    exit_with_fault(e, 'Terminate', opts)
    6370except RuntimeError, e:
    6471    sys.exit("Error processing RPC: %s" % e)
     
    7279        out.close()
    7380        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/fedd_to_abac.py

    rac15159 r0a49bd7  
    77import os.path
    88import subprocess
     9from tempfile import mkdtemp
    910
    1011from string import join
    11 from optparse import OptionParser
    12 
    13 from federation.util import abac_pem_type, abac_split_cert
    14 
    15 class Parser(OptionParser):
     12
     13from federation.authorizer import abac_authorizer
     14from federation.util import abac_pem_type, abac_split_cert, file_expanding_opts
     15
     16class Parser(file_expanding_opts):
    1617    def __init__(self):
    17         OptionParser.__init__(self)
     18        file_expanding_opts.__init__(self)
    1819        self.add_option('--cert', dest='cert', default=None,
     20                action='callback', callback=self.expand_file, type='str',
    1921                help='my fedid as an X.509 certificate')
    2022        self.add_option('--key', dest='key', default=None,
     23                action='callback', callback=self.expand_file, type='str',
    2124                help='key for the certificate')
    2225        self.add_option('--dir', dest='dir', default=None,
     26                action='callback', callback=self.expand_file, type='str',
    2327                help='Output directory for credentials')
    24         self.add_option('--make-dir', action='store_true', dest='make_dir',
     28        self.add_option('--make_dir', action='store_true', dest='make_dir',
    2529                default=False, help='Create the --dir directory')
    2630        self.add_option('--debug', action='store_true', dest='debug',
    2731                default=False, help='Just print the creddy commands')
     32        self.add_option('--policy_only', action='store_const', const=False,
     33                dest='make_authorizer', default=True,
     34                help='Only create the directory of certs, " + \
     35                        "do not create an authorizer')
     36        self.add_option('--update', action='store_const', const=True,
     37                dest='update_authorizer', default=False,
     38                help='Add the generated policy to an existing authorizer')
    2839
    2940class identity:
     
    3849        return "%s: %s" % (self.name, join(self.roles, ', '))
    3950
    40 comment_re = re.compile('^\s*#|^$')
    41 fedid_str = 'fedid:([0-9a-fA-F]{40})'
    42 id_str = '[a-zA-Z][\w_-]*'
    43 single_re = re.compile('\s*%s\s*->\s*(%s)' % (fedid_str, id_str))
    44 double_re = re.compile('\s*%s\s*->\s*\((%s)\s*,\s*(%s)\)' % \
    45         (fedid_str, id_str, id_str))
    46 bad_role = re.compile('[^a-zA-Z0-9_]+')
     51def clear_dir(dir):
     52    for path, dirs, files in os.walk(dir, topdown=False):
     53        for f in files: os.unlink(os.path.join(path, f))
     54        for d in dirs: os.rmdir(os.path.join(path, d))
     55
     56def parse_configs(files):
     57    """
     58    Step through each file pulling the roles out of the database lines, if any,
     59    and creating (or appending to) identity objects, one identity in a dict for
     60    each  fedid.  Return that dict.  May raise an exception when file
     61    difficulties occur.
     62    """
     63    comment_re = re.compile('^\s*#|^$')
     64    fedid_str = 'fedid:([0-9a-fA-F]{40})'
     65    id_str = '[a-zA-Z][\w_-]*'
     66    single_re = re.compile('\s*%s\s*->\s*(%s)' % (fedid_str, id_str))
     67    double_re = re.compile('\s*%s\s*->\s*\((%s)\s*,\s*(%s)\)' % \
     68            (fedid_str, id_str, id_str))
     69    bad_role = re.compile('[^a-zA-Z0-9_]+')
     70
     71    roles = { }
     72
     73    for fn in files:
     74        f = open(fn, "r")
     75        for l in f:
     76            id = None
     77            for r in (comment_re, single_re, double_re):
     78                m = r.match(l)
     79                if m:
     80                    # NB, the comment_re has no groups
     81                    if m.groups():
     82                        g = m.groups()
     83                        id = g[0]
     84                        r = [ bad_role.sub('_', x) for x in g[1:] ]
     85                    break
     86            else:
     87                print 'Unmatched line: %s' % l
     88
     89            if id:
     90                # New and create are implicit.  >sigh<
     91                r.extend(('new', 'create'))
     92                if id in roles: roles[id].add_roles(r)
     93                else: roles[id] = identity(r[0], r)
     94
     95    return roles
     96
     97def make_credentials(roles, cert, key, creds_dir, debug):
     98    """
     99    From the dict of identities, indexed by fedid, call creddy to create the
     100    ABAC certificates.  Return a list of the created files.  If debug is true,
     101    just print the creddy commands.
     102    """
     103    credfiles = []
     104    for k, id in roles.items():
     105        for i, r in enumerate(id.roles):
     106            cf = '%s/%s%03d_attr.der' % \
     107                    (creds_dir or 'new_cert_dir', id.name, i)
     108            cmd = ['creddy', '--attribute',
     109                    '--issuer=%s' % (cert or 'cert_file'),
     110                    '--key=%s' % (key or 'key_file'), '--role=%s' % r,
     111                    '--subject-id=%s' % k, '--out=%s' % cf ]
     112            if debug:
     113                print join(cmd)
     114            else:
     115                rv =  subprocess.call(cmd)
     116                if rv != 0:
     117                    raise RuntimeError('%s failed: %d' % (join(cmd), rv))
     118                else:
     119                    credfiles.append(cf)
     120    return credfiles
    47121
    48122parser = Parser()
     
    51125delete_certs = False
    52126
    53 
     127if not opts.make_authorizer and opts.update_authorizer:
     128    sys.exit('--policy_only and --update are in conflict.  Pick one.')
    54129
    55130if opts.key:
    56131    if os.access(opts.key, os.R_OK): key = opts.key
    57132    else: sys.exit('Cannot read %s (key file)' % opts.key)
     133
     134if opts.make_authorizer:
     135    creds_dir = mkdtemp()
     136    delete_creds = True
     137else:
     138    creds_dir = opts.dir
     139    delete_creds = False
     140
     141if opts.cert:
     142    if os.access(opts.cert, os.R_OK):
     143        if not key:
     144            if abac_pem_type(opts.cert) == 'both':
     145                key, cert = abac_split_cert(opts.cert)
     146                delete_certs = True
     147        else:
     148            cert = opts.cert
     149    else:
     150        sys.exit('Cannot read %s (certificate file)' % opts.cert)
     151
     152if any([ x is None for x in (cert, opts.dir, key)]):
     153    print >>sys.stderr, "Need output dir, certificate and key to make creds"
     154    print >>sys.stderr, "Reverting to debug mode"
     155    debug = True
     156else:
     157    debug = opts.debug
    58158
    59159if opts.dir:
     
    70170            sys.exit('%s is not writable' % opts.dir)
    71171
    72 if opts.cert:
    73     if os.access(opts.cert, os.R_OK):
    74         if not key:
    75             if abac_pem_type(opts.cert) == 'both':
    76                 key, cert = abac_split_cert(opts.cert)
    77                 delete_certs = True
    78         else:
    79             cert = opts.cert
    80     else:
    81         sys.exit('Cannot read %s (certificate file)' % opts.cert)
    82 
    83 if any([ x is None for x in (cert, opts.dir, key)]):
    84     print >>sys.stderr, "Need output dir, certificate and key to make creds"
    85     print >>sys.stderr, "Reverting to debug mode"
    86     debug = True
    87 else:
    88     debug = opts.debug
    89 
    90 roles = { }
     172
    91173try:
    92     for fn in args:
    93         try:
    94             f = open(fn, "r")
    95             for l in f:
    96                 id = None
    97                 for r in (comment_re, single_re, double_re):
    98                     m = r.match(l)
    99                     if m:
    100                         if m.groups():
    101                             g = m.groups()
    102                             id = g[0]
    103                             r = [ bad_role.sub('_', x) for x in g[1:] ]
    104                         break
    105                 else:
    106                     print 'Unmatched line: %s' % l
    107                 if id:
    108                     # New and create are implicit.  >sigh<
    109                     r.extend(('new', 'create'))
    110                     if id in roles: roles[id].add_roles(r)
    111                     else: roles[id] = identity(r[0], r)
    112 
    113         except EnvironmentError, e:
    114             print >>sys.stderr, 'Cannot open file (%s): %s' % \
    115                     (e.filename, e.strerror)
    116 
     174    roles = parse_configs(args)
    117175    if not roles:
    118176        print >>sys.stderr, "No roles found.  Did you specify a configuration?"
    119177
    120     for k, id in roles.items():
    121         for i, r in enumerate(id.roles):
    122             cmd = ['creddy', '--attribute',
    123                     '--issuer=%s' % (cert or 'cert_file'),
    124                     '--key=%s' % (key or 'key_file'), '--role=%s' % r,
    125                     '--subject-id=%s' % k,
    126                     '--out=%s/%s%03d_attr.der' % \
    127                             (opts.dir or 'new_cert_dir', id.name, i)]
     178    try:
     179        credfiles = make_credentials(roles, cert, key, creds_dir, debug)
     180
     181        if opts.make_authorizer:
    128182            if debug:
    129                 print join(cmd)
     183                print >>sys.stderr, 'Debug mode, no authorizer created'
     184            elif opts.update_authorizer:
     185                operation = 'updat'
     186                a = abac_authorizer(load=opts.dir)
     187                a.import_credentials(file_list=credfiles)
     188                a.save()
    130189            else:
    131                 rv =  subprocess.call(cmd)
    132                 if rv != 0:
    133                     sys.exit('%s failed: %d' % (join(cmd), rv))
     190                operation = 'creat'
     191                a = abac_authorizer(key=opts.key, me=opts.cert,
     192                        certs=creds_dir, save=opts.dir)
     193                a.save()
     194    except EnvironmentError, e:
     195        sys.exit("Can't create or write %s: %s" % (e.filename,
     196            e.strerror))
     197    except abac_authorizer.bad_cert_error, e:
     198        sys.exit("Error %sing authorizer: %s" % (op, e))
     199    except RuntimeError, e:
     200        sys.exit('%s' % e)
     201
    134202finally:
    135203    if delete_certs:
    136204        if cert: os.unlink(cert)
    137205        if key: os.unlink(key)
     206    if delete_creds:
     207        clear_dir(creds_dir)
     208        os.rmdir(creds_dir)
  • fedd/federation/access.py

    rac15159 r0a49bd7  
    234234                        "Unpickling failed: %s") % e)
    235235
     236    def append_allocation_authorization(self, aid, attrs,
     237            need_state_lock=False, write_state_file=False, state_attr='state'):
     238        """
     239        Append the authorization information to system state.  By default we
     240        assume this is called with the state lock and with a write of the state
     241        file in the near future, need_state_lock and write_state_file can
     242        override this.  The state_attr is the attribute in the access class
     243        that holds the per allocation information.  Some complex classes use
     244        different names for the dict.
     245        """
     246
     247        for p, a in attrs:
     248            self.auth.set_attribute(p, a)
     249        self.auth.save()
     250
     251        if need_state_lock: self.state_lock.acquire()
     252        d = getattr(self, state_attr)
     253        if aid in d and 'auth' in d[aid]:
     254            d[aid]['auth'].update(attrs)
     255        if write_state_file: self.write_state()
     256        if need_state_lock: self.state_lock.release()
     257
     258    def clear_allocation_authorization(self, aid, need_state_lock=False,
     259            write_state_file=False, state_attr='state'):
     260        """
     261        Attrs is a set of attribute principal pairs that need to be removed
     262        from the authenticator.  Remove them and save the authenticator.  See
     263        append_allocation_authorization for the various overrides.
     264        """
     265
     266        if need_state_lock: self.state_lock.acquire()
     267        d = getattr(self, state_attr)
     268        if aid in d and 'auth' in d[aid]:
     269            for p, a in d[aid]['auth']:
     270                self.auth.unset_attribute(p, a)
     271            d[aid]['auth'] = set()
     272        if write_state_file: self.write_state()
     273        if need_state_lock: self.state_lock.release()
     274        self.auth.save()
     275
    236276    def lookup_access(self, req, fid, filter=None, compare=None):
    237277        """
     
    261301        # Check every attribute that we know how to map and take the first
    262302        # success.
     303        fail_proofs = [ ]
    263304        for attr in check:
    264             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:
    265308                self.log.debug("Access succeeded for %s %s" % (attr.attr, fid))
    266309                # XXX: needs to deal with dynamics
    267310                return copy.copy(attr.value), (False, False, False), \
    268                         [ fid ]
     311                        [ fid ], proof
    269312            else:
     313                fail_proofs.append(proof)
    270314                self.log.debug("Access failed for %s %s" % (attr.attr, fid))
    271315        else:
    272             raise service_error(service_error.access, "Access denied")
     316            raise service_error(service_error.access, "Access denied",
     317                    proof=fail_proofs)
    273318
    274319
     
    408453        return (exp, state)
    409454
    410     def build_access_response(self, alloc_id, ap, services):
     455    def build_access_response(self, alloc_id, ap, services, proof):
    411456        """
    412457        Create the SOAP response.
     
    421466        msg = {
    422467                'allocID': alloc_id,
     468                'proof': proof.to_dict(),
    423469                'fedAttr': [
    424470                    { 'attribute': 'domain', 'value': self.domain } ,
     
    730776        except EnvironmentError, e:
    731777            self.log.error("Error deleting directory tree in %s" % e);
     778
     779    def RequestAccess(self, req, fid):
     780        """
     781        Handle an access request.  Success here maps the requester into the
     782        local access control space and establishes state about that user keyed
     783        to a fedid.  We also save a copy of the certificate underlying that
     784        fedid so this allocation can access configuration information and
     785        shared parameters on the experiment controller.
     786        """
     787
     788        # The dance to get into the request body
     789        if req.has_key('RequestAccessRequestBody'):
     790            req = req['RequestAccessRequestBody']
     791        else:
     792            raise service_error(service_error.req, "No request!?")
     793
     794        # Base class lookup routine.  If this fails, it throws a service
     795        # exception denying access that triggers a fault response back to the
     796        # caller.
     797        found, match, owners, proof = self.lookup_access(req, fid)
     798        self.log.info(
     799                "[RequestAccess] Access granted to %s with local creds %s" % \
     800                (match, found))
     801        # Make a fedid for this allocation
     802        allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
     803        aid = unicode(allocID)
     804
     805        # Store the data about this allocation:
     806        self.state_lock.acquire()
     807        self.state[aid] = { }
     808        self.state[aid]['user'] = found
     809        self.state[aid]['owners'] = owners
     810        self.state[aid]['auth'] = set()
     811        # Authorize the creating fedid and the principal representing the
     812        # allocation to manipulate it.
     813        self.append_allocation_authorization(aid,
     814                ((fid, allocID), (allocID, allocID)))
     815        self.write_state()
     816        self.state_lock.release()
     817
     818        # Create a directory to stash the certificate in, ans stash it.
     819        try:
     820            f = open("%s/%s.pem" % (self.certdir, aid), "w")
     821            print >>f, alloc_cert
     822            f.close()
     823        except EnvironmentError, e:
     824            raise service_error(service_error.internal,
     825                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
     826        self.log.debug('[RequestAccess] Returning allocation ID: %s' % allocID)
     827        return { 'allocID': { 'fedid': allocID }, 'proof': proof.to_dict() }
     828
     829    def ReleaseAccess(self, req, fid):
     830        """
     831        Release the allocation granted earlier.  Access to the allocation is
     832        checked and if valid, the state and cached certificate are destroyed.
     833        """
     834        # The dance to get into the request body
     835        if req.has_key('ReleaseAccessRequestBody'):
     836            req = req['ReleaseAccessRequestBody']
     837        else:
     838            raise service_error(service_error.req, "No request!?")
     839
     840        # Pull a key out of the request.  One can request to delete an
     841        # allocation by a local human readable name or by a fedid.  This finds
     842        # both choices.
     843        try:
     844            if 'localname' in req['allocID']:
     845                auth_attr = aid = req['allocID']['localname']
     846            elif 'fedid' in req['allocID']:
     847                aid = unicode(req['allocID']['fedid'])
     848                auth_attr = req['allocID']['fedid']
     849            else:
     850                raise service_error(service_error.req,
     851                        "Only localnames and fedids are understood")
     852        except KeyError:
     853            raise service_error(service_error.req, "Badly formed request")
     854
     855        self.log.debug("[ReleaseAccess] deallocation requested for %s", aid)
     856        #  Confirm access
     857        access_ok, proof = self.auth.check_attribute(fid, auth_attr,
     858                with_proof=True)
     859        if not access_ok:
     860            self.log.debug("[ReleaseAccess] deallocation denied for %s", aid)
     861            raise service_error(service_error.access, "Access Denied",
     862                    proof=proof)
     863
     864        # If there is an allocation in the state, delete it.  Note the locking.
     865        self.state_lock.acquire()
     866        if aid in self.state:
     867            self.log.debug("[ReleaseAccess] Found allocation for %s" %aid)
     868            self.clear_allocation_authorization(aid)
     869            del self.state[aid]
     870            self.write_state()
     871            self.state_lock.release()
     872            # And remove the access cert
     873            cf = "%s/%s.pem" % (self.certdir, aid)
     874            self.log.debug("[ReleaseAccess] Removing %s" % cf)
     875            os.remove(cf)
     876            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
     877        else:
     878            self.state_lock.release()
     879            raise service_error(service_error.req, "No such allocation")
  • fedd/federation/authorizer.py

    rac15159 r0a49bd7  
    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):
     
    209218        if self.me is not None and abac_pem_type(self.me) == 'both':
    210219            if self.save_dir:
    211                 self.key, self.me = abac_split_cert(self.me,
    212                         keyfile="%s/key.pem" % self.save_dir,
    213                         certfile = "%s/cert.pem" % self.save_dir)
     220                keyfile="%s/key.pem" % self.save_dir
     221                certfile = "%s/cert.pem" % self.save_dir
     222
     223                # Clear a spot for the new key and cert files.
     224                for fn in (keyfile, certfile):
     225                    if os.access(fn, os.F_OK):
     226                        os.unlink(fn)
     227
     228                self.key, self.me = abac_split_cert(self.me, keyfile, certfile)
    214229            else:
    215230                raise abac_authorizer.bad_cert_error("Combination " + \
     
    223238            if rv != 0:
    224239                raise abac_authorizer.bad_name(
    225                         'Cannot load identity from %s' % me.cert)
     240                        'Cannot load identity from %s' % me)
    226241        else:
    227242            self.fedid = None
     
    235250        if load:
    236251            self.load(load)
     252
     253    # Modify the pickling operations so that the context and lock are not
     254    # pickled
     255
     256    def __getstate__(self):
     257        d = self.__dict__.copy()
     258        del d['lock']
     259        del d['context']
     260        return d
     261
     262    def __setstate__(self, d):
     263        # Import everything from the pickle dict (except what we excluded in
     264        # __getstate__)
     265        self.__dict__.update(d)
     266        # Initialize the unpicklables
     267        self.context = ABAC.Context()
     268        self.lock = Lock()
    237269
    238270    @staticmethod
     
    352384
    353385
    354     def check_attribute(self, name, attr):
    355         # XXX proof soon
     386    def check_attribute(self, name, attr, with_proof=False):
    356387        if isinstance(name, tuple):
    357388            raise abac_authorizer.bad_name(
     
    376407            # Sigh. Unicode vs swig and swig seems to lose.  Make sure
    377408            # everything we pass into ABAC is a str not a unicode.
    378             rv, proof = self.context.query(a, n)
     409            rv, p = self.context.query(a, n)
    379410            # XXX delete soon
    380             if not rv and attr in self.globals: rv = True
    381             self.lock.release()
    382 
    383             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
    384417
    385418    def set_global_attribute(self, attr):
     
    421454            if not os.access(dir, os.F_OK):
    422455                os.mkdir(dir)
    423             # These are unpicklable, so set them aside
    424             context = self.context
    425             lock = self.lock
    426             self.context = None
    427             self.lock = None
    428456
    429457            f = open("%s/state" % dir, "w")
     
    433461            if not os.access("%s/certs" %dir, os.F_OK):
    434462                os.mkdir("%s/certs" % dir)
    435             seenid = set()
    436             seenattr = set()
    437 
    438             #restore unpicklable state
    439             self.context = context
    440             self.lock = lock
    441             #remove old certs
     463
     464            # Clear the certs subdir
    442465            for fn in [ f for f in os.listdir("%s/certs" % dir) \
    443466                    if abac_authorizer.cred_file_re.match(f)]:
    444467                os.unlink('%s/certs/%s' % (dir, fn))
     468
     469            # Save the context
    445470            ii = 0
    446471            ai = 0
     472            seenid = set()
     473            seenattr = set()
    447474            for c in self.context.credentials():
    448475                id = c.issuer_cert()
     
    463490                    seenattr.add(attr)
    464491        except EnvironmentError, e:
    465             # If we've mislaid self.lock, release lock (they're the same object)
    466             if self.lock: self.lock.release()
    467             elif lock: lock.release()
     492            self.lock.release()
    468493            raise e
    469494        except pickle.PickleError, e:
    470             # If we've mislaid self.lock, release lock (they're the same object)
    471             if self.lock: self.lock.release()
    472             elif lock: lock.release()
     495            self.lock.release()
    473496            raise e
    474497        self.lock.release()
  • fedd/federation/client_lib.py

    rac15159 r0a49bd7  
    77
    88from string import join
     9from datetime import datetime
    910
    1011
    1112from fedid import fedid
    12 from util import fedd_ssl_context
     13from util import fedd_ssl_context, file_expanding_opts
    1314from remote_service import service_caller
    1415from service_error import service_error
     
    1718
    1819
    19 class client_opts(OptionParser):
     20class client_opts(file_expanding_opts):
    2021    """
    2122    Standatd set of options that all clients talking to fedd can probably use.
    2223    Client code usually specializes this.
    2324    """
     25
    2426    def __init__(self):
    25         OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
     27        file_expanding_opts.__init__(self,
     28                usage="%prog [opts] (--help for details)",
    2629                version="0.1")
    2730
    28         self.add_option("--cert", action="store", dest="cert",
     31        self.add_option("--cert", action="callback", dest="cert",
     32                callback=self.expand_file,
    2933                type="string", help="my certificate file")
    30         self.add_option("--abac", action="store", dest="abac_dir",
    31                 type="string", help="Directory with abac certs")
     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")
     37        self.add_option("--abac", action="callback", dest="abac_dir",
     38                callback=self.expand_file,
     39                type="string", default=os.path.expanduser('~/.abac'),
     40                help="Directory with abac certs")
     41        self.add_option('--no_abac', action='store_const', const=None,
     42                dest='abac_dir', help='Do not use abac authorization')
    3243        self.add_option( "--debug", action="count", dest="debug",
    3344                default=0, help="Set debug.  Repeat for more information")
     
    3546                dest="serialize_only", default=False,
    3647                help="Print the SOAP request that would be sent and exit")
    37         self.add_option("--trusted", action="store", dest="trusted",
     48        self.add_option("--trusted", action="callback", dest="trusted",
     49                callback=self.expand_file,
    3850                type="string", help="Trusted certificates (required)")
    3951        self.add_option("--url", action="store", dest="url",
     
    4557                const=sys.stderr, help="Print SOAP exchange to stderr")
    4658
    47 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):
    4871    """
    4972    Print an error message and exit.  exc is the RPCException that caused the
     
    6487        code = -1
    6588
     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
    6696    print>>out, codestr
    6797    print>>out, "Description: %s" % exc.desc
     
    73103    XMLPRC calls.
    74104    """
    75     def __init__(self, desc=None, code=None, errstr=None):
     105    def __init__(self, desc=None, code=None, errstr=None, proof=None):
    76106        RuntimeError.__init__(self)
    77107        self.desc = desc
     
    79109        else: self.code = -1
    80110        self.errstr = errstr
     111        self.proof = proof
    81112
    82113class CertificateMismatchError(RuntimeError): pass
     
    98129    '''
    99130    rv = [ ]
    100     if dir:
     131    if dir and os.path.isdir(dir):
    101132        for fn in ["%s/%s" % (dir, p) for p in os.listdir(dir) \
    102133                if os.path.isfile("%s/%s" % (dir,p))]:
     
    138169    elif 'FEDD_URL' in os.environ: url = os.environ['FEDD_URL']
    139170    else: url = default_url
     171
     172    if opts.abac_dir:
     173        if not os.access(opts.abac_dir, os.F_OK):
     174            raise RuntimeError("No ABAC directory: %s" % opts.abac_dir)
     175        elif not os.path.isdir(opts.abac_dir):
     176            raise RuntimeError("ABAC directory not a directory: %s" \
     177                    % opts.abac_dir)
     178        elif not os.access(opts.abac_dir, os.W_OK):
     179            raise RuntimeError("Cannot write to ABAC directory: %s" \
     180                    % opts.abac_dir)
     181
    140182
    141183
     
    189231            except service_error, e:
    190232                raise RPCException(desc=e.desc, code=e.code,
    191                         errstr=e.code_string())
     233                        errstr=e.code_string(), proof=e.proof)
    192234    elif transport == "xmlrpc":
    193235        if serialize_only:
  • fedd/federation/deter_internal_access.py

    rac15159 r0a49bd7  
    142142            }
    143143
    144     def RequestAccess(self, req, fid):
    145         """
    146         Handle the access request.  Proxy if not for us.
    147 
    148         Parse out the fields and make the allocations or rejections if for us,
    149         otherwise, assuming we're willing to proxy, proxy the request out.
    150         """
    151 
    152         # The dance to get into the request body
    153         if req.has_key('RequestAccessRequestBody'):
    154             req = req['RequestAccessRequestBody']
    155         else:
    156             raise service_error(service_error.req, "No request!?")
    157 
    158         found, match, owners = self.lookup_access(req, fid)
    159         # keep track of what's been added
    160         allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
    161         aid = unicode(allocID)
    162 
    163         self.state_lock.acquire()
    164         self.state[aid] = { }
    165         self.state[aid]['user'] = found
    166         self.state[aid]['owners'] = owners
    167         self.state[aid]['vlan'] = None
    168         self.write_state()
    169         self.state_lock.release()
    170         self.auth.set_attribute(fid, allocID)
    171         self.auth.set_attribute(allocID, allocID)
    172         self.auth.save()
    173 
    174         try:
    175             f = open("%s/%s.pem" % (self.certdir, aid), "w")
    176             print >>f, alloc_cert
    177             f.close()
    178         except EnvironmentError, e:
    179             raise service_error(service_error.internal,
    180                     "Can't open %s/%s : %s" % (self.certdir, aid, e))
    181         return { 'allocID': { 'fedid': allocID } }
    182 
    183     def ReleaseAccess(self, req, fid):
    184         # The dance to get into the request body
    185         if req.has_key('ReleaseAccessRequestBody'):
    186             req = req['ReleaseAccessRequestBody']
    187         else:
    188             raise service_error(service_error.req, "No request!?")
    189 
    190         # Local request
    191         try:
    192             if req['allocID'].has_key('localname'):
    193                 auth_attr = aid = req['allocID']['localname']
    194             elif req['allocID'].has_key('fedid'):
    195                 aid = unicode(req['allocID']['fedid'])
    196                 auth_attr = req['allocID']['fedid']
    197             else:
    198                 raise service_error(service_error.req,
    199                         "Only localnames and fedids are understood")
    200         except KeyError:
    201             raise service_error(service_error.req, "Badly formed request")
    202 
    203         self.log.debug("[access] deallocation requested for %s", aid)
    204         if not self.auth.check_attribute(fid, auth_attr):
    205             self.log.debug("[access] deallocation denied for %s", aid)
    206             raise service_error(service_error.access, "Access Denied")
    207 
    208         self.state_lock.acquire()
    209         if self.state.has_key(aid):
    210             self.log.debug("Found allocation for %s" %aid)
    211             del self.state[aid]
    212             self.write_state()
    213             self.state_lock.release()
    214             # And remove the access cert
    215             cf = "%s/%s.pem" % (self.certdir, aid)
    216             self.log.debug("Removing %s" % cf)
    217             os.remove(cf)
    218             return { 'allocID': req['allocID'] }
    219         else:
    220             self.state_lock.release()
    221             raise service_error(service_error.req, "No such allocation")
     144    # RequestAccess and ReleaseAccess come from the base
    222145
    223146    def extract_parameters(self, top):
     
    292215        aid = "%s" % auth_attr
    293216        attrs = req.get('fedAttr', [])
    294         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:
    295220            raise service_error(service_error.access, "Access denied")
    296221        else:
     
    348273                'allocID': req['allocID'],
    349274                'allocationLog': logv,
    350                 'segmentdescription': { 'topdldescription': rtopo.to_dict() }
     275                'segmentdescription': { 'topdldescription': rtopo.to_dict() },
     276                'proof': proof.to_dict(),
    351277                }
    352278        retval = copy.deepcopy(self.state[aid]['started'])
     
    366292
    367293        self.log.debug("Terminate request for %s" %aid)
    368         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:
    369297            raise service_error(service_error.access, "Access denied")
    370298
     
    385313        self.state[aid]['vlan'] = None
    386314        self.state_lock.release()
    387         return { 'allocID': req['allocID'] }
     315        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/dragon_access.py

    rac15159 r0a49bd7  
    122122        else: raise self.parse_error("Repo should be in parens");
    123123
    124     def RequestAccess(self, req, fid):
    125         """
    126         Handle the access request.
    127 
    128         Parse out the fields and make the allocations or rejections if for us,
    129         otherwise, assuming we're willing to proxy, proxy the request out.
    130         """
    131 
    132         # The dance to get into the request body
    133         if req.has_key('RequestAccessRequestBody'):
    134             req = req['RequestAccessRequestBody']
    135         else:
    136             raise service_error(service_error.req, "No request!?")
    137 
    138         if req.has_key('destinationTestbed'):
    139             dt = unpack_id(req['destinationTestbed'])
    140 
    141         # Request for this fedd
    142         found, match, owners = self.lookup_access(req, fid)
    143         # keep track of what's been added
    144         allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
    145         aid = unicode(allocID)
    146 
    147         self.state_lock.acquire()
    148         self.state[aid] = { }
    149         self.state[aid]['user'] = found
    150         self.state[aid]['owners'] = owners
    151         self.write_state()
    152         self.state_lock.release()
    153         self.auth.set_attribute(fid, allocID)
    154         self.auth.set_attribute(allocID, allocID)
    155         self.auth.save()
    156 
    157         try:
    158             f = open("%s/%s.pem" % (self.certdir, aid), "w")
    159             print >>f, alloc_cert
    160             f.close()
    161         except EnvironmentError, e:
    162             raise service_error(service_error.internal,
    163                     "Can't open %s/%s : %s" % (self.certdir, aid, e))
    164         return { 'allocID': { 'fedid': allocID } }
    165 
    166     def ReleaseAccess(self, req, fid):
    167         # The dance to get into the request body
    168         if req.has_key('ReleaseAccessRequestBody'):
    169             req = req['ReleaseAccessRequestBody']
    170         else:
    171             raise service_error(service_error.req, "No request!?")
    172 
    173         try:
    174             if req['allocID'].has_key('localname'):
    175                 auth_attr = aid = req['allocID']['localname']
    176             elif req['allocID'].has_key('fedid'):
    177                 aid = unicode(req['allocID']['fedid'])
    178                 auth_attr = req['allocID']['fedid']
    179             else:
    180                 raise service_error(service_error.req,
    181                         "Only localnames and fedids are understood")
    182         except KeyError:
    183             raise service_error(service_error.req, "Badly formed request")
    184 
    185         self.log.debug("[access] deallocation requested for %s", aid)
    186         if not self.auth.check_attribute(fid, auth_attr):
    187             self.log.debug("[access] deallocation denied for %s", aid)
    188             raise service_error(service_error.access, "Access Denied")
    189 
    190         self.state_lock.acquire()
    191         if self.state.has_key(aid):
    192             self.log.debug("Found allocation for %s" %aid)
    193             del self.state[aid]
    194             self.write_state()
    195             self.state_lock.release()
    196             # And remove the access cert
    197             cf = "%s/%s.pem" % (self.certdir, aid)
    198             self.log.debug("Removing %s" % cf)
    199             os.remove(cf)
    200             return { 'allocID': req['allocID'] }
    201         else:
    202             self.state_lock.release()
    203             raise service_error(service_error.req, "No such allocation")
     124    # RequestAccess and ReleaseAccess come from the base class
    204125
    205126    def extract_parameters(self, top):
     
    497418        return (repo, alloc_log)
    498419
    499     def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id):
     420    def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id, proof):
    500421        """
    501422        Place the relevant information in the global state block, and prepare
     
    521442                    'topdldescription': rtopo.to_dict()
    522443                    },
     444                'proof': proof.to_dict(),
    523445                }
    524446        retval = copy.deepcopy(self.state[aid]['started'])
     
    541463        aid = "%s" % auth_attr
    542464        attrs = req.get('fedAttr', [])
    543         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:
    544468            raise service_error(service_error.access, "Access denied")
    545469        else:
     
    587511        if gri:
    588512            return self.finalize_experiment(topo, vlan_no, gri, aid,
    589                     req['allocID'])
     513                    req['allocID'], proof)
    590514        elif err:
    591515            raise service_error(service_error.federant,
     
    605529        self.log.debug("Terminate request for %s" %aid)
    606530        attrs = req.get('fedAttr', [])
    607         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:
    608534            raise service_error(service_error.access, "Access denied")
    609535
     
    628554        self.log.debug("Stop segment for GRI: %s" %gri)
    629555        self.stop_segment(user, gri)
    630         return { 'allocID': req['allocID'] }
     556        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/emulab_access.py

    rac15159 r0a49bd7  
    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
     
    254255                    'Bad mapping (unbalanced parens or more than 1 comma)')
    255256
    256 
    257257    # RequestAccess support routines
    258258
     
    384384        self.state_lock.acquire()
    385385        self.allocation[aid] = { }
     386        self.allocation[aid]['auth'] = set()
    386387        try:
    387388            pname = ap['project']['name']['localname']
     
    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,
     
    511513        for k, v in svc_state.items():
    512514            self.allocation[aid][k] = v
     515        self.append_allocation_authorization(aid,
     516                set([(o, allocID) for o in owners]), state_attr='allocation')
    513517        self.write_state()
    514518        self.state_lock.release()
    515         # Give the owners the right to change this allocation
    516         for o in owners:
    517             self.auth.set_attribute(o, allocID)
    518         self.auth.save()
    519519        try:
    520520            f = open("%s/%s.pem" % (self.certdir, aid), "w")
     
    525525                    "Can't open %s/%s : %s" % (self.certdir, aid, e))
    526526        resp = self.build_access_response({ 'fedid': allocID } ,
    527                 ap, services)
     527                ap, services, proof)
    528528        return resp
    529529
     
    572572        self.log.debug("[access] deallocation requested for %s by %s" % \
    573573                (aid, fid))
    574         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:
    575577            self.log.debug("[access] deallocation denied for %s", aid)
    576578            raise service_error(service_error.access, "Access Denied")
     
    591593        if aid in self.allocation:
    592594            self.log.debug("Found allocation for %s" %aid)
     595            self.clear_allocation_authorization(aid, state_attr='allocation')
    593596            for k in self.allocation[aid]['keys']:
    594597                kk = "%s:%s" % k
     
    625628            self.log.debug("Removing %s" % cf)
    626629            os.remove(cf)
    627             return { 'allocID': req['allocID'] }
     630            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    628631        else:
    629632            self.state_lock.release()
     
    9981001        return (ename, proj, user, pubkey_base, secretkey_base, alloc_log)
    9991002
    1000     def finalize_experiment(self, starter, topo, aid, alloc_id):
     1003    def finalize_experiment(self, starter, topo, aid, alloc_id, proof):
    10011004        """
    10021005        Store key bits of experiment state in the global repository, including
     
    10231026                    'topdldescription': topo.clone().to_dict()
    10241027                    },
    1025                 'embedding': embedding
     1028                'embedding': embedding,
     1029                'proof': proof.to_dict(),
    10261030                }
    10271031        retval = copy.copy(self.allocation[aid]['started'])
     
    10471051        aid = "%s" % auth_attr
    10481052        attrs = req.get('fedAttr', [])
    1049         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:
    10501057            raise service_error(service_error.access, "Access denied")
    10511058        else:
     
    11131120
    11141121        if rv:
    1115             return self.finalize_experiment(starter, topo, aid, req['allocID'])
     1122            return self.finalize_experiment(starter, topo, aid, req['allocID'],
     1123                    proof)
    11161124        elif err:
    11171125            raise service_error(service_error.federant,
     
    11291137        aid = "%s" % auth_attr
    11301138        attrs = req.get('fedAttr', [])
    1131         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:
    11321143            raise service_error(service_error.access, "Access denied")
    11331144
     
    11581169                debug=self.create_debug, boss=self.boss, cert=self.xmlrpc_cert)
    11591170        stopper(self, user, proj, ename)
    1160         return { 'allocID': req['allocID'] }
     1171        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/experiment_control.py

    rac15159 r0a49bd7  
    151151        accessdb_file = config.get("experiment_control", "accessdb")
    152152
    153         self.ssh_pubkey_file = config.get("experiment_control",
    154                 "ssh_pubkey_file")
    155         self.ssh_privkey_file = config.get("experiment_control",
    156                 "ssh_privkey_file")
    157153        dt = config.get("experiment_control", "direct_transit")
    158154        self.auth_type = config.get('experiment_control', 'auth_type') \
     
    209205            raise service_error(service_error.internal,
    210206                    "Unknown auth_type: %s" % self.auth_type)
    211 
    212 
    213         if self.ssh_pubkey_file:
    214             try:
    215                 f = open(self.ssh_pubkey_file, 'r')
    216                 self.ssh_pubkey = f.read()
    217                 f.close()
    218             except EnvironmentError:
    219                 raise service_error(service_error.internal,
    220                         "Cannot read sshpubkey")
    221         else:
    222             raise service_error(service_error.internal,
    223                     "No SSH public key file?")
    224 
    225         if not self.ssh_privkey_file:
    226             raise service_error(service_error.internal,
    227                     "No SSH public key file?")
    228 
    229207
    230208        if mapdb_file:
     
    801779            self.response = None
    802780            self.node = { }
     781            self.proof = None
    803782
    804783        def make_map(self, resp):
     
    850829                            self.log_collector.write(line)
    851830                    self.make_map(r['StartSegmentResponseBody'])
     831                    if 'proof' in r: self.proof = r['proof']
    852832                    self.response = r
    853833                else:
     
    10211001            # mapping.
    10221002            embedding = [ ]
     1003            proofs = { }
    10231004            for s in starters:
    10241005                for k, v in s.node.items():
     
    10281009                        'testbed': s.testbed
    10291010                        })
     1011                if s.proof:
     1012                    proofs[s.testbed] = s.proof
    10301013            log.info("[start_segment]: Experiment %s active" % eid)
    10311014
     
    10441027                top.to_dict()
    10451028        self.state[eid]['embedding'] = embedding
     1029        # Append startup proofs
     1030        for f in self.state[eid]['federant']:
     1031            if 'name' in f and 'localname' in f['name']:
     1032                if f['name']['localname'] in proofs:
     1033                    f['proof'].append(proofs[f['name']['localname']])
     1034
    10461035        if self.state_filename: self.write_state()
    10471036        self.state_lock.release()
     
    10611050        if isinstance(e.software, list): e.software.extend(s)
    10621051        else: e.software = s
     1052
     1053    def append_experiment_authorization(self, expid, attrs,
     1054            need_state_lock=True):
     1055        """
     1056        Append the authorization information to system state
     1057        """
     1058
     1059        for p, a in attrs:
     1060            self.auth.set_attribute(p, a)
     1061        self.auth.save()
     1062
     1063        if need_state_lock: self.state_lock.acquire()
     1064        self.state[expid]['auth'].update(attrs)
     1065        if self.state_filename: self.write_state()
     1066        if need_state_lock: self.state_lock.release()
     1067
     1068    def clear_experiment_authorization(self, expid, need_state_lock=True):
     1069        """
     1070        Attrs is a set of attribute principal pairs that need to be removed
     1071        from the authenticator.  Remove them and save the authenticator.
     1072        """
     1073
     1074        if need_state_lock: self.state_lock.acquire()
     1075        if expid in self.state and 'auth' in self.state[expid]:
     1076            for p, a in self.state[expid]['auth']:
     1077                self.auth.unset_attribute(p, a)
     1078            self.state[expid]['auth'] = set()
     1079        if self.state_filename: self.write_state()
     1080        if need_state_lock: self.state_lock.release()
     1081        self.auth.save()
    10631082
    10641083
     
    10871106                status = self.state[eid].get('experimentStatus', None)
    10881107                if status and status == 'failed':
    1089                     # remove the old access attribute
    1090                     self.auth.unset_attribute(fid, old_expid)
    1091                     self.auth.save()
     1108                    # remove the old access attributes
     1109                    self.clear_experiment_authorization(eid,
     1110                            need_state_lock=False)
    10921111                    overwrite = True
    10931112                    del self.state[eid]
     
    11051124                    'owner': fid,
    11061125                    'log' : [],
     1126                    'auth': set(),
    11071127                }
    11081128            self.state[expid] = self.state[eid]
    1109             if self.state_filename: self.write_state()
    1110             self.state_lock.release()
     1129            if self.state_filename: self.write_state()
     1130            self.state_lock.release()
    11111131        else:
    11121132            eid = self.exp_stem
     
    11261146                    'owner': fid,
    11271147                    'log' : [],
     1148                    'auth': set(),
    11281149                }
    11291150            self.state[expid] = self.state[eid]
    1130             if self.state_filename: self.write_state()
    1131             self.state_lock.release()
     1151            if self.state_filename: self.write_state()
     1152            self.state_lock.release()
     1153
     1154        # Let users touch the state.  Authorize this fid and the expid itself
     1155        # to touch the experiment, as well as allowing th eoverrides.
     1156        self.append_experiment_authorization(eid,
     1157                set([(fid, expid), (expid,expid)] + \
     1158                        [ (o, expid) for o in self.overrides]))
    11321159
    11331160        return eid
     
    12881315            raise service_error(service_error.protocol,
    12891316                        "Bad proxy response")
     1317        if 'proof' not in r:
     1318            raise service_error(service_error.protocol,
     1319                        "Bad access response (no access proof)")
    12901320       
    12911321        tbparam[tb] = {
    12921322                "allocID" : r['allocID'],
    12931323                "uri": uri,
     1324                "proof": [ r['proof'] ],
    12941325                }
    12951326
     
    13371368            topo[tb].make_indices()
    13381369
     1370    def confirm_software(self, top):
     1371        """
     1372        Make sure that the software to be loaded in the topo is all available
     1373        before we begin making access requests, etc.  This is a subset of
     1374        wrangle_software.
     1375        """
     1376        pkgs = set([ d for i, d in self.fedkit + self.gatewaykit ])
     1377        pkgs.update([x.location for e in top.elements for x in e.software])
     1378
     1379        for pkg in pkgs:
     1380            loc = pkg
     1381
     1382            scheme, host, path = urlparse(loc)[0:3]
     1383            dest = os.path.basename(path)
     1384            if not scheme:
     1385                if not loc.startswith('/'):
     1386                    loc = "/%s" % loc
     1387                loc = "file://%s" %loc
     1388            # NB: if scheme was found, loc == pkg
     1389            try:
     1390                u = urlopen(loc)
     1391                u.close()
     1392            except Exception, e:
     1393                raise service_error(service_error.req,
     1394                        "Cannot open %s: %s" % (loc, e))
     1395        return True
     1396
    13391397    def wrangle_software(self, expid, top, topo, tbparams):
    13401398        """
     
    13491407        softdir ="%s/%s" % ( self.repodir, linkpath)
    13501408        softmap = { }
    1351         # These are in a list of tuples format (each kit).  This comprehension
    1352         # unwraps them into a single list of tuples that initilaizes the set of
    1353         # tuples.
    1354         pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \
    1355                 for p, t in l ])
    1356         pkgs.update([x.location for e in top.elements \
    1357                 for x in e.software])
     1409
     1410        # self.fedkit and self.gateway kit are lists of tuples of
     1411        # (install_location, download_location) this extracts the download
     1412        # locations.
     1413        pkgs = set([ d for i, d in self.fedkit + self.gatewaykit ])
     1414        pkgs.update([x.location for e in top.elements for x in e.software])
    13581415        try:
    13591416            os.makedirs(softdir)
     
    13621419                    "Cannot create software directory: %s" % e)
    13631420        # The actual copying.  Everything's converted into a url for copying.
     1421        auth_attrs = set()
    13641422        for pkg in pkgs:
    13651423            loc = pkg
     
    13711429                    loc = "/%s" % loc
    13721430                loc = "file://%s" %loc
     1431            # NB: if scheme was found, loc == pkg
    13731432            try:
    13741433                u = urlopen(loc)
     
    13941453                    ( self.repo_url, path, dest)
    13951454
    1396             # Allow the individual segments to access the software.
    1397             for tb in tbparams.keys():
    1398                 self.auth.set_attribute(tbparams[tb]['allocID']['fedid'],
    1399                         "/%s/%s" % ( path, dest))
    1400             self.auth.save()
     1455            # Allow the individual segments to access the software by assigning
     1456            # an attribute to each testbed allocation that encodes the data to
     1457            # be released.  This expression collects the data for each run of
     1458            # the loop.
     1459            auth_attrs.update([
     1460                (tbparams[tb]['allocID']['fedid'], "/%s/%s" % ( path, dest)) \
     1461                        for tb in tbparams.keys()])
     1462
     1463        self.append_experiment_authorization(expid, auth_attrs)
    14011464
    14021465        # Convert the software locations in the segments into the local
     
    14281491            self.auth.save()
    14291492
    1430         if not self.auth.check_attribute(fid, 'new'):
    1431             raise service_error(service_error.access, "New access denied")
     1493        access_ok, proof = self.auth.check_attribute(fid, 'new',
     1494                with_proof=True)
     1495
     1496        if not access_ok:
     1497            raise service_error(service_error.access, "New access denied",
     1498                    proof=[proof])
    14321499
    14331500        try:
     
    14681535                state='empty')
    14691536
    1470         # Let users touch the state
    1471         self.auth.set_attribute(fid, expid)
    1472         self.auth.set_attribute(expid, expid)
    1473         # Override fedids can manipulate state as well
    1474         for o in self.overrides:
    1475             self.auth.set_attribute(o, expid)
    1476         self.auth.save()
    1477 
    14781537        rv = {
    14791538                'experimentID': [
     
    14811540                ],
    14821541                'experimentStatus': 'empty',
    1483                 'experimentAccess': { 'X509' : expcert }
     1542                'experimentAccess': { 'X509' : expcert },
     1543                'proof': proof.to_dict(),
    14841544            }
    14851545
     
    16091669        return top
    16101670
    1611     def get_testbed_services(self, req):
     1671    def get_testbed_services(self, req, testbeds):
    16121672        """
    16131673        Parse the services section of the request into into two dicts mapping
     
    17001760                    "Cannot copy keyfiles: %s" % e)
    17011761
    1702         # Allow the individual testbeds to access the configuration files.
    1703         for tb in tbparams.keys():
    1704             asignee = tbparams[tb]['allocID']['fedid']
    1705             for f in ("hosts", gw_secretkey_base, gw_pubkey_base):
    1706                 self.auth.set_attribute(asignee, "%s/%s" % \
    1707                         (configpath, f))
    1708             self.auth.save()
     1762        # Allow the individual testbeds to access the configuration files,
     1763        # again by setting an attribute for the relevant pathnames on each
     1764        # allocation principal.  Yeah, that's a long list comprehension.
     1765        self.append_experiment_authorization(expid, set([
     1766            (tbparams[tb]['allocID']['fedid'], "%s/%s" % (configpath, f)) \
     1767                    for tb in tbparams.keys() \
     1768                        for f in ("hosts", gw_secretkey_base, gw_pubkey_base)]))
    17091769
    17101770        attrs = [
     
    17521812            raise service_error(service_error.req, "No request?")
    17531813
    1754         self.check_experiment_access(fid, key)
     1814        proof = self.check_experiment_access(fid, key)
    17551815
    17561816        self.state_lock.acquire()
    17571817        if self.state.has_key(key):
    17581818            if self.state[key].has_key('vtopo'):
    1759                 rv = { 'experiment' : {keytype: key },\
    1760                         'vtopo': self.state[key]['vtopo'],\
     1819                rv = { 'experiment' : {keytype: key },
     1820                        'vtopo': self.state[key]['vtopo'],
     1821                        'proof': proof.to_dict(),
    17611822                    }
    17621823            else:
     
    17961857            raise service_error(service_error.req, "No request?")
    17971858
    1798         self.check_experiment_access(fid, key)
     1859        proof = self.check_experiment_access(fid, key)
    17991860
    18001861        self.state_lock.acquire()
    18011862        if self.state.has_key(key):
    18021863            if self.state[key].has_key('vis'):
    1803                 rv =  { 'experiment' : {keytype: key },\
    1804                         'vis': self.state[key]['vis'],\
     1864                rv =  { 'experiment' : {keytype: key },
     1865                        'vis': self.state[key]['vis'],
     1866                        'proof': proof.to_dict(),
    18051867                        }
    18061868            else:
     
    18231885        between when it was started and the beginning of resource allocation.
    18241886        This is basically the information about each local allocation.  This
    1825         fills in the values of the placeholder allocation in the state.
     1887        fills in the values of the placeholder allocation in the state.  It
     1888        also collects the access proofs and returns them as dicts for a
     1889        response message.
    18261890        """
    18271891        # save federant information
     
    18311895                    'allocID' : tbparams[k]['allocID'],
    18321896                    'uri': tbparams[k]['uri'],
     1897                    'proof': tbparams[k]['proof'],
    18331898                }
    18341899
     
    18411906                [ tbparams[tb]['federant'] for tb in tbparams.keys() \
    18421907                    if tbparams[tb].has_key('federant') ]
     1908        # Access proofs for the response message
     1909        proofs = [copy.deepcopy(p) for k in tbparams.keys()\
     1910                    for p in tbparams[k]['federant']['proof']]
    18431911        if self.state_filename:
    18441912            self.write_state()
    18451913        self.state_lock.release()
     1914        return proofs
    18461915
    18471916    def clear_placeholder(self, eid, expid, tmpdir):
     
    18831952
    18841953        # Make sure that the caller can talk to us
    1885         self.check_experiment_access(fid, key)
     1954        proof = self.check_experiment_access(fid, key)
    18861955
    18871956        # Install the testbed map entries supplied with the request into a copy
     
    19111980
    19121981            top = self.get_topology(req, tmpdir)
     1982            self.confirm_software(top)
    19131983            # Assign the IPs
    19141984            hosts, ip_allocator = self.allocate_ips_to_topo(top)
     
    19241994                        testbeds.append(tb)
    19251995
    1926             masters, pmasters = self.get_testbed_services(req)
     1996            masters, pmasters = self.get_testbed_services(req, testbeds)
    19271997            allocated = { }         # Testbeds we can access
    19281998            topo ={ }               # Sub topologies
    19291999            connInfo = { }          # Connection information
    19302000
     2001            self.split_topology(top, topo, testbeds)
     2002
    19312003            self.get_access_to_testbeds(testbeds, fid, allocated,
    19322004                    tbparams, masters, tbmap, expid, expcert_file)
    1933 
    1934             self.split_topology(top, topo, testbeds)
    19352005
    19362006            attrs = self.generate_keys_and_hosts(tmpdir, expid, hosts, tbparams)
     
    19402010            part.add_portals(top, topo, eid, pmasters, tbparams, ip_allocator,
    19412011                    connInfo, expid)
     2012
     2013            auth_attrs = set()
    19422014            # Now get access to the dynamic testbeds (those added above)
    19432015            for tb in [ t for t in topo if t not in allocated]:
     
    19482020                # Give the testbed access to keys it exports or imports
    19492021                if store_keys:
    1950                     for sk in store_keys.split(" "):
    1951                         self.auth.set_attribute(\
    1952                                 tbparams[tb]['allocID']['fedid'], sk)
    1953             self.auth.save()
     2022                    auth_attrs.update(set([
     2023                        (tbparams[tb]['allocID']['fedid'], sk) \
     2024                                for sk in store_keys.split(" ")]))
     2025
     2026            if auth_attrs:
     2027                self.append_experiment_authorization(expid, auth_attrs)
    19542028
    19552029            # transit and disconnected testbeds may not have a connInfo entry.
     
    19632037            vtopo = topdl.topology_to_vtopo(top)
    19642038            vis = self.genviz(vtopo)
    1965             self.save_federant_information(allocated, tbparams, eid, vtopo,
    1966                     vis, top)
     2039            proofs = self.save_federant_information(allocated, tbparams,
     2040                    eid, vtopo, vis, top)
    19672041        except service_error, e:
    19682042            # If something goes wrong in the parse (usually an access error)
     
    19752049        # Start the background swapper and return the starting state.  From
    19762050        # here on out, the state will stick around a while.
    1977 
    1978         # Let users touch the state
    1979         self.auth.set_attribute(fid, expid)
    1980         self.auth.set_attribute(expid, expid)
    1981         # Override fedids can manipulate state as well
    1982         for o in self.overrides:
    1983             self.auth.set_attribute(o, expid)
    1984         self.auth.save()
    19852051
    19862052        # Create a logger that logs to the experiment's state object as well as
     
    20082074                ],
    20092075                'experimentStatus': 'starting',
     2076                'proof': [ proof.to_dict() ] + proofs,
    20102077            }
    20112078
     
    20532120            key = self.get_experiment_fedid(key)
    20542121
    2055         if self.auth.check_attribute(fid, key):
    2056             return True
     2122        access_ok, proof = self.auth.check_attribute(fid, key, with_proof=True)
     2123
     2124        if access_ok:
     2125            return proof
    20572126        else:
    2058             raise service_error(service_error.access, "Access Denied")
     2127            raise service_error(service_error.access, "Access Denied",
     2128                proof)
    20592129
    20602130
     
    20652135        """
    20662136        self.log.info("Get handler %s %s" % (path, fid))
     2137        # XXX: log proofs?
    20672138        if self.auth.check_attribute(fid, path):
    20682139            return ("%s/%s" % (self.repodir, path), "application/binary")
     
    20702141            return (None, None)
    20712142
    2072     def clean_info_response(self, rv):
     2143    def clean_info_response(self, rv, proof):
    20732144        """
    20742145        Remove the information in the experiment's state object that is not in
     
    20772148        # Remove the owner info (should always be there, but...)
    20782149        if rv.has_key('owner'): del rv['owner']
     2150        if 'auth' in rv: del rv['auth']
    20792151
    20802152        # Convert the log into the allocationLog parameter and remove the
     
    20932165                if f.has_key('allocID'): del f['allocID']
    20942166                if f.has_key('uri'): del f['uri']
     2167        rv['proof'] = proof.to_dict()
    20952168
    20962169        return rv
     
    21192192            raise service_error(service_error.req, "No request?")
    21202193
    2121         self.check_experiment_access(fid, key)
     2194        proof = self.check_experiment_access(fid, key)
    21222195
    21232196        # The state may be massaged by the service function that called
     
    21302203
    21312204        if rv:
    2132             return self.clean_info_response(rv)
     2205            return self.clean_info_response(rv, proof)
    21332206        else:
    21342207            raise service_error(service_error.req, "No such experiment")
     
    21382211        Return all the stored info that this fedid can access
    21392212        """
    2140         rv = { 'info': [ ] }
     2213        rv = { 'info': [ ], 'proof': [ ] }
    21412214
    21422215        self.state_lock.acquire()
    21432216        for key in [ k for k in self.state.keys() if isinstance(k, fedid)]:
    21442217            try:
    2145                 self.check_experiment_access(fid, key)
     2218                proof = self.check_experiment_access(fid, key)
    21462219            except service_error, e:
    21472220                if e.code == service_error.access:
     
    21532226            if self.state.has_key(key):
    21542227                e = copy.deepcopy(self.state[key])
    2155                 e = self.clean_info_response(e)
     2228                e = self.clean_info_response(e, proof)
    21562229                rv['info'].append(e)
     2230                rv['proof'].append(proof.to_dict())
    21572231        self.state_lock.release()
    21582232        return rv
     
    22822356            if tmpdir: self.remove_dirs(tmpdir)
    22832357
    2284 
    22852358    def terminate_experiment(self, req, fid):
    22862359        """
     
    22952368
    22962369        key = self.get_experiment_key(req, 'experiment')
    2297         self.check_experiment_access(fid, key)
     2370        proof = self.check_experiment_access(fid, key)
    22982371        exp = req.get('experiment', False)
    22992372        force = req.get('force', False)
     
    23262399            self.state_lock.acquire()
    23272400            for id in ids:
     2401                self.clear_experiment_authorization(id, need_state_lock=False)
    23282402                if id in self.state: del self.state[id]
    23292403
     
    23462420            if repo:
    23472421                self.remove_dirs("%s/%s" % (self.repodir, repo))
    2348                
     2422       
    23492423            return {
    23502424                    'experiment': exp ,
    23512425                    'deallocationLog': string.join(dealloc_list, ''),
     2426                    'proof': [proof.to_dict()],
    23522427                    }
    23532428        else:
     
    23682443        rv = { 'name': name }
    23692444
    2370         if name and self.auth.check_attribute(fid, name):
     2445        if not name:
     2446            raise service_error(service_error.req, "No name?")
     2447
     2448        access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True)
     2449
     2450        if access_ok:
    23712451            self.log.debug("[GetValue] asking for %s " % name)
    23722452            try:
     
    23782458            if v is not None:
    23792459                rv['value'] = v
     2460            rv['proof'] = proof.to_dict()
    23802461            self.log.debug("[GetValue] got %s from %s" % (v, name))
    23812462            return rv
    23822463        else:
    2383             raise service_error(service_error.access, "Access Denied")
     2464            raise service_error(service_error.access, "Access Denied",
     2465                    proof=proof)
    23842466       
    23852467
     
    23962478        v = req.get('value', '')
    23972479
    2398         if name and self.auth.check_attribute(fid, name):
     2480        if not name:
     2481            raise service_error(service_error.req, "No name?")
     2482
     2483        access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True)
     2484
     2485        if access_ok:
    23992486            try:
    24002487                self.synch_store.set_value(name, v)
     
    24092496                raise service_error(service_error.federant,
    24102497                        "Synch key %s revoked" % name)
    2411             return { 'name': name, 'value': v }
     2498                return { 'name': name, 'value': v, 'proof': proof.to_dict() }
    24122499        else:
    2413             raise service_error(service_error.access, "Access Denied")
     2500            raise service_error(service_error.access, "Access Denied",
     2501                    proof=proof)
  • fedd/federation/ns2topdl.py

    rac15159 r0a49bd7  
    1111from remote_service import xmlrpc_handler, soap_handler
    1212from service_error import *
    13 from authorizer import authorizer
     13from authorizer import authorizer, abac_authorizer
    1414
    1515
     
    3131        self.tcl_splitter = config.get("ns2topdl", "tcl_splitter",
    3232                "/usr/testbed/lib/ns2ir/parse.tcl")
     33        self.auth_type = config.get('ns2topdl', 'auth_type') or 'legacy'
    3334        access_db = config.get("ns2topdl", "accessdb", None)
    34         allow_any = config.getboolean("ns2topdl", "allow_any", False)
     35        self.allow_any = config.getboolean("ns2topdl", "allow_any", False)
     36        auth_dir = config.get('ns2topdl', 'auth_dir')
    3537
    3638        self.log = logging.getLogger("fedd.ns2topdl")
     
    4749                    "using local one")
    4850
    49         if access_db and allow_any:
     51
     52        if self.auth_type == 'legacy':
     53            if access_db and self.allow_any:
     54                raise service_error(service_error.internal,
     55                        "Cannot specify both an access database and " +
     56                        "allow_any for ns2topdl")
     57           
     58            if access_db:
     59                try:
     60                    read_simple_accessdb(access_db, self.auth, 'ns2topdl')
     61                except EnvironmentError, e:
     62                    raise service_error(service_error.internal,
     63                            "Error reading accessDB %s: %s" % (access_db, e))
     64                except ValueError:
     65                    raise service_error(service_error.internal, "%s" % e)
     66            elif self.allow_any:
     67                auth.set_global_attribute("ns2topdl")
     68        elif self.auth_type == 'abac':
     69            self.auth = abac_authorizer(load=auth_dir)
     70        else:
    5071            raise service_error(service_error.internal,
    51                     "Cannot specify both an access database and allow_any " +\
    52                             "for ns2topdl")
    53        
    54         if access_db:
    55             try:
    56                 read_simple_accessdb(access_db, self.auth, 'ns2topdl')
    57             except EnvironmentError, e:
    58                 raise service_error(service_error.internal,
    59                         "Error reading accessDB %s: %s" % (access_db, e))
    60             except ValueError:
    61                 raise service_error(service_error.internal, "%s" % e)
    62         elif allow_any:
    63             auth.set_global_attribute("ns2topdl")
     72                    "Unknown auth_type: %s" % self.auth_type)
    6473
    6574
     
    8190        """
    8291
    83         if not self.auth.check_attribute(fid, 'ns2topdl'):
    84             raise service_error(service_error.access, "Access Denied")
     92        if self.allow_any:
     93            self.auth.set_attribute(fid, 'ns2topdl')
     94
     95        access_ok, proof = self.auth.check_attribute(fid, 'ns2topdl',
     96            with_proof=True)
     97
     98        if not access_ok:
     99            raise service_error(service_error.access, "Access Denied",
     100                proof=proof)
    85101
    86102        try:
     
    137153                'experimentdescription':  {
    138154                    'topdldescription': top.to_dict(),
    139                     }
     155                    },
     156                'proof': proof.to_dict(),
    140157                }
    141158
  • fedd/federation/parse_detail.py

    rac15159 r0a49bd7  
    11#!/usr/local/bin/python
    22
    3 from fedd_client import *
     3try:
     4    from fedd_services import *
     5except ImportError:
     6    from fedd_client import *
    47
    58from ZSI.TC import QName, String, URI, AnyElement, UNBOUNDED, Any
  • fedd/federation/protogeni_access.py

    rac15159 r0a49bd7  
    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)
     
    275276        # The list of owner FIDs
    276277        self.allocation[aid]['owners'] = owners
     278        self.allocation[aid]['auth'] = set()
     279        self.append_allocation_authorization(aid,
     280                ((fid, allocID), (allocID, allocID)), state_attr='allocation')
    277281        self.write_state()
    278282        self.state_lock.release()
    279         self.auth.set_attribute(fid, allocID)
    280         self.auth.set_attribute(allocID, allocID)
    281         self.auth.save()
    282283
    283284        try:
     
    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")
     
    319322        if self.allocation.has_key(aid):
    320323            self.log.debug("Found allocation for %s" %aid)
     324            self.clear_allocation_authorization(aid, state_attr='allocation')
    321325            del self.allocation[aid]
    322326            self.write_state()
     
    326330            self.log.debug("Removing %s" % cf)
    327331            os.remove(cf)
    328             return { 'allocID': req['allocID'] }
     332            return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    329333        else:
    330334            self.state_lock.release()
     
    12501254                cpw, alloc_log)
    12511255
    1252     def finalize_experiment(self, topo, nodes, aid, alloc_id):
     1256    def finalize_experiment(self, topo, nodes, aid, alloc_id, proof):
    12531257        # Copy the assigned names into the return topology
    12541258        rvtopo = topo.clone()
     
    12721276                    'topdldescription': rvtopo.to_dict() },
    12731277                'embedding': embedding,
     1278                'proof': proof.to_dict(),
    12741279                }
    12751280        retval = copy.deepcopy(self.allocation[aid]['started'])
     
    12941299        aid = "%s" % auth_attr
    12951300        attrs = req.get('fedAttr', [])
    1296         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:
    12971304            raise service_error(service_error.access, "Access denied")
    12981305        else:
     
    13551362
    13561363        if rv:
    1357             return self.finalize_experiment(topo, nodes, aid, req['allocID'])
     1364            return self.finalize_experiment(topo, nodes, aid, req['allocID'],
     1365                    proof)
    13581366        elif err:
    13591367            raise service_error(service_error.federant,
     
    13911399        aid = "%s" % auth_attr
    13921400        attrs = req.get('fedAttr', [])
    1393         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:
    13941404            raise service_error(service_error.access, "Access denied")
    13951405
     
    14181428        self.stop_segment(segment_commands, user, staging, slice_cred,
    14191429                slice_urn, cf, cpw)
    1420         return { 'allocID': req['allocID'] }
     1430        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
    14211431
    14221432    def renew_segment(self, segment_commands, name, scred, slice_urn, interval,
  • fedd/federation/remote_service.py

    rac15159 r0a49bd7  
    1616import httplib
    1717
     18from proof import proof
    1819from service_error import service_error
    1920from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary
     
    2122    import fedd_services
    2223    import fedd_internal_services
     24    service_port_name = 'getfeddPortType'
     25    internal_service_port_name = 'getfeddInternalPortType'
    2326except ImportError:
    24     import fedd_server
    2527    import fedd_client
     28    import fedd_internal_client
     29    fedd_services = fedd_client
     30    fedd_internal_services = fedd_internal_client
     31    service_port_name = 'getfeddPort'
     32    internal_service_port_name = 'getfedd_internalPort'
    2633
    2734from util import fedd_ssl_context
     
    6067    # A map used to encapsulate fedids into xmlrpclib.Binary objects
    6168    encap_fedids = (('fedid', to_binary),)
     69
     70    # fields that are never unicoded, because they represent non strings.
     71    do_not_unicode = set(['credential'])
    6272
    6373    @staticmethod
     
    166176        if isinstance(obj, dict):
    167177            for k in obj.keys():
    168                 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])
    169180            return obj
    170181        elif isinstance(obj, basestring) and not isinstance(obj, unicode):
     
    283294        self.service_name = service_name
    284295
     296<<<<<<< HEAD
    285297        try:
    286298            if getattr(fedd_services.feddBindingSOAP, service_name, None):
     
    300312                self.port_name = 'getfedd_internalPort'
    301313
     314=======
     315        if getattr(fedd_services.feddBindingSOAP, service_name, None):
     316            self.locator = fedd_services.feddServiceLocator
     317            self.port_name = service_port_name
     318        elif getattr(fedd_internal_services.feddInternalBindingSOAP,
     319                service_name, None):
     320            self.locator = fedd_internal_services.feddInternalServiceLocator
     321            self.port_name = internal_service_port_name
     322>>>>>>> 944b746d2f97c5803ca28f587dd7100a57e25a69
    302323
    303324        if request_message: self.request_message = request_message
    304325        else:
    305326            request_message_name = "%sRequestMessage" % service_name
     327<<<<<<< HEAD
    306328            try:
    307329                self.request_message = \
     
    314336                        getattr(fedd_internal_client, request_message_name,
    315337                                None)
     338=======
     339            self.request_message = \
     340                    getattr(fedd_services, request_message_name, None) or \
     341                    getattr(fedd_internal_services, request_message_name,
     342                            None)
     343>>>>>>> 944b746d2f97c5803ca28f587dd7100a57e25a69
    316344            if not self.request_message and strict:
    317345                raise service_error(service_error.internal,
     
    523551                            'desc': e.fault.string or "Something Weird" }
    524552                if ee:
     553                    if 'proof' in ee:
     554                        pl = [ proof.from_dict(p) for p in ee['proof']]
     555                    else:
     556                        pl = None
    525557                    raise service_error(ee.get('code', 'no code'),
    526                             ee.get('desc','no desc'))
     558                            ee.get('desc','no desc'), proof=pl)
    527559                else:
    528560                    raise service_error(service_error.internal,
  • fedd/federation/server.py

    rac15159 r0a49bd7  
    1313
    1414from fedid import fedid
    15 from fedd_services import ns0
     15
     16# ZSI uses a deprecated multifile interface.  This shuts the warning system up.
     17from warnings import filterwarnings
     18filterwarnings("ignore", ".*multifile.*", DeprecationWarning, "ZSI")
     19
     20try:
     21    from fedd_services import ns0
     22except ImportError:
     23    from fedd_server import ns0
     24
    1625from service_error import *
    1726
     
    127136            self.send_fault(f)
    128137            resp = None
    129        
     138
    130139        if resp != None:
    131140            sw = SoapWriter()
     
    192201                de._errstr=e.code_string()
    193202                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]
    194212                if  e.is_server_error():
    195213                    raise Fault(Fault.Server, e.code_string(), detail=de)
  • fedd/federation/service_error.py

    rac15159 r0a49bd7  
    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

    rac15159 r0a49bd7  
    163163            }
    164164
    165     def RequestAccess(self, req, fid):
    166         """
    167         Handle an access request.  Success here maps the requester into the
    168         local access control space and establishes state about that user keyed
    169         to a fedid.  We also save a copy of the certificate underlying that
    170         fedid so this allocation can access configuration information and
    171         shared parameters on the experiment controller.
    172         """
    173 
    174         # The dance to get into the request body
    175         if req.has_key('RequestAccessRequestBody'):
    176             req = req['RequestAccessRequestBody']
    177         else:
    178             raise service_error(service_error.req, "No request!?")
    179 
    180         # Base class lookup routine.  If this fails, it throws a service
    181         # exception denying access that triggers a fault response back to the
    182         # caller.
    183         found, match, owners = self.lookup_access(req, fid)
    184         self.log.info(
    185                 "[RequestAccess] Access granted to %s with local creds %s" % \
    186                 (match, found))
    187         # Make a fedid for this allocation
    188         allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
    189         aid = unicode(allocID)
    190 
    191         # Store the data about this allocation:
    192         self.state_lock.acquire()
    193         self.state[aid] = { }
    194         self.state[aid]['user'] = found
    195         self.state[aid]['owners'] = owners
    196         self.write_state()
    197         self.state_lock.release()
    198         # Authorize the creating fedid and the principal representing the
    199         # allocation to manipulate it.
    200         self.auth.set_attribute(fid, allocID)
    201         self.auth.set_attribute(allocID, allocID)
    202         self.auth.save()
    203 
    204         # Create a directory to stash the certificate in, ans stash it.
    205         try:
    206             f = open("%s/%s.pem" % (self.certdir, aid), "w")
    207             print >>f, alloc_cert
    208             f.close()
    209         except EnvironmentError, e:
    210             raise service_error(service_error.internal,
    211                     "Can't open %s/%s : %s" % (self.certdir, aid, e))
    212         self.log.debug('[RequestAccess] Returning allocation ID: %s' % allocID)
    213         return { 'allocID': { 'fedid': allocID } }
    214 
    215     def ReleaseAccess(self, req, fid):
    216         """
    217         Release the allocation granted earlier.  Access to the allocation is
    218         checked and if valid, the state and cached certificate are destroyed.
    219         """
    220         # The dance to get into the request body
    221         if req.has_key('ReleaseAccessRequestBody'):
    222             req = req['ReleaseAccessRequestBody']
    223         else:
    224             raise service_error(service_error.req, "No request!?")
    225 
    226         # Pull a key out of the request.  One can request to delete an
    227         # allocation by a local human readable name or by a fedid.  This finds
    228         # both choices.
    229         try:
    230             if 'localname' in req['allocID']:
    231                 auth_attr = aid = req['allocID']['localname']
    232             elif 'fedid' in req['allocID']:
    233                 aid = unicode(req['allocID']['fedid'])
    234                 auth_attr = req['allocID']['fedid']
    235             else:
    236                 raise service_error(service_error.req,
    237                         "Only localnames and fedids are understood")
    238         except KeyError:
    239             raise service_error(service_error.req, "Badly formed request")
    240 
    241         self.log.debug("[ReleaseAccess] deallocation requested for %s", aid)
    242         #  Confirm access
    243         if not self.auth.check_attribute(fid, auth_attr):
    244             self.log.debug("[ReleaseAccess] deallocation denied for %s", aid)
    245             raise service_error(service_error.access, "Access Denied")
    246 
    247         # If there is an allocation in the state, delete it.  Note the locking.
    248         self.state_lock.acquire()
    249         if aid in self.state:
    250             self.log.debug("[ReleaseAccess] Found allocation for %s" %aid)
    251             del self.state[aid]
    252             self.write_state()
    253             self.state_lock.release()
    254             # And remove the access cert
    255             cf = "%s/%s.pem" % (self.certdir, aid)
    256             self.log.debug("[ReleaseAccess] Removing %s" % cf)
    257             os.remove(cf)
    258             return { 'allocID': req['allocID'] }
    259         else:
    260             self.state_lock.release()
    261             raise service_error(service_error.req, "No such allocation")
     165    # RequestAccess and ReleaseAccess come from the base class
    262166
    263167    def StartSegment(self, req, fid):
     
    279183        aid = "%s" % auth_attr
    280184        # Authorization check
    281         if not self.auth.check_attribute(fid, auth_attr):
    282             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)
    283190        else:
    284191            # See if this is a replay of an earlier succeeded StartSegment -
     
    338245                'allocID': req['allocID'],
    339246                'allocationLog': "Allocatation complete",
    340                 'segmentdescription': { 'topdldescription': topo.to_dict() }
     247                'segmentdescription': { 'topdldescription': topo.to_dict() },
     248                'proof': proof.to_dict(),
    341249                }
    342250        retval = copy.deepcopy(self.state[aid]['started'])
     
    362270        self.log.debug("Terminate request for %s" %aid)
    363271        # Check authorization
    364         if not self.auth.check_attribute(fid, auth_attr):
    365             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)
    366277
    367278        # Authorized: remove the integer from the allocation.  A more complex
     
    377288        self.state_lock.release()
    378289   
    379         return { 'allocID': req['allocID'] }
     290        return { 'allocID': req['allocID'], 'proof': proof.to_dict() }
  • fedd/federation/thread_pool.py

    rac15159 r0a49bd7  
    44import time
    55from threading import Lock, Thread, Condition
     6from service_error import service_error
    67
    78class thread_pool:
  • fedd/federation/util.py

    rac15159 r0a49bd7  
    88
    99import httplib
     10
     11from optparse import OptionParser
    1012
    1113from socket import sslerror
     
    9597            self.set_allow_unknown_ca(True)
    9698            self.set_verify(SSL.verify_peer, 10, callback=callb)
     99
     100class file_expanding_opts(OptionParser):
     101    def expand_file(self, option, opt_str, v, p):
     102        """
     103        Store the given value to the given destination after expanding home
     104        directories.
     105        """
     106        setattr(p.values, option.dest, os.path.expanduser(v))
     107
     108    def __init__(self, usage=None, version=None):
     109        OptionParser.__init__(self)
     110
    97111
    98112def read_simple_accessdb(fn, auth, mask=[]):
     
    360374    # This should be a one-iteration loop
    361375    for c in context.credentials():
    362         ids.add(c.issuer_cert())
    363         attrs.add(c.attribute_cert())
     376        ids.add(str(c.issuer_cert()))
     377        attrs.add(str(c.attribute_cert()))
    364378
    365379    return list(ids), list(attrs)
  • fedd/init_abac_authorizer.py

    rac15159 r0a49bd7  
    44import os, os.path
    55
    6 from optparse import OptionParser
     6from federation.util import file_expanding_opts
    77from federation.authorizer import abac_authorizer
    88
    9 class Parser(OptionParser):
     9class Parser(file_expanding_opts):
    1010    def __init__(self):
    11         OptionParser.__init__(self, usage='%prog [options]')
    12         self.add_option('--cert', dest='cert', help='Identity certificate')
    13         self.add_option('--key', dest='key', help='Identity key')
     11        file_expanding_opts.__init__(self, usage='%prog [options]')
     12        self.add_option('--cert', dest='cert',
     13                action='callback', callback=self.expand_file, type='str',
     14                help='Identity certificate')
     15        self.add_option('--key', dest='key',
     16                action='callback', callback=self.expand_file, type='str',
     17                help='Identity key')
    1418        self.add_option('--policy', dest='policy',
     19                action='callback', callback=self.expand_file, type='str',
    1520                help='ABAC policy certificates')
    16         self.add_option('--dir', dest='out_dir', help='directory to save into')
     21        self.add_option('--dir', dest='out_dir',
     22                action='callback', callback=self.expand_file, type='str',
     23                help='directory to save into')
    1724
    1825parser = Parser()
  • fedd/setup.py

    rac15159 r0a49bd7  
    44
    55setup(name='fedd',
    6         version='3.01',
     6        version='3.20a',
    77        description='DETER Federation daemon',
    88        author='Ted Faber',
     
    1313        requires=['ZSI(>=2.0)', 'M2Crypto'],
    1414        provides=['federation'],
    15         scripts=['confirm_sshkey.py', 'exp_access_db.py', 'fedd.py',
    16             'fedd_client.py', 'fedd_create.py', 'fedd_ftopo.py',
     15        scripts=['access_to_abac.py', 'cert_to_fedid.py', 'confirm_sshkey.py',
     16            'creddy_split.py', 'dump_abac_authorizer.py', 'exp_access_db.py',
     17            'fedd.py', 'fedd_client.py', 'fedd_create.py', 'fedd_ftopo.py',
    1718            'fedd_image.py', 'fedd_info.py', 'fedd_multiinfo.py',
    1819            'fedd_multistatus.py', 'fedd_new.py', 'fedd_ns2topdl.py',
    19             'fedd_spewlog.py', 'fedd_terminate.py',
    20             'fedid.py', 'user_to_project.py' ],
     20            'fedd_spewlog.py', 'fedd_terminate.py', 'fedd_to_abac.py',
     21            'fedid.py', 'fedd_to_abac.py', 'user_to_project.py' ],
    2122    )
  • wsdl/fedd_types.xsd

    rac15159 r0a49bd7  
    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.