Changeset 353db8c for fedd


Ignore:
Timestamp:
Nov 23, 2010 5:00:48 PM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
6e63513
Parents:
3ff5e2a
Message:

Vairous ABAC tweaks, mostly concerned with making key splitting less visible.

Location:
fedd
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • fedd/access_to_abac.py

    r3ff5e2a r353db8c  
    5151            return "%s.%s <- %s" % (self.principal, self.attr, self.req)
    5252
    53 # Mappinng generation functiona and the access parser throw these when there is
     53# Mappinng generation function and the access parser throw these when there is
    5454# a parsing problem.
    5555class parse_error(RuntimeError): pass
  • fedd/creddy_split.py

    r3ff5e2a r353db8c  
    66
    77from optparse import OptionParser
     8from federation.util import abac_split_cert, abac_pem_type
    89
    910# Options
     
    2021                        'default: [%default]'))
    2122
    22 class diversion:
    23     '''
    24     Wraps up the reqular expression to start and end a diversion, as well as
    25     the open file that gets the lines.
    26     '''
    27     def __init__(self, start, end, fn):
    28         self.start = re.compile(start)
    29         self.end = re.compile(end)
    30         self.f = open(fn, 'w')
    31 
    3223# Option validation
    3324parser = Parser()
     
    4031    sys.exit('\nMust have one file argument')
    4132
    42 if not opts.force:
    43     for fn in (opts.cert, opts.key):
    44         if os.access(fn, os.F_OK):
    45             sys.exit('%s exists.  --force to overwite it' % fn)
     33for fn in (opts.cert, opts.key):
     34    if os.access(fn, os.F_OK):
     35        if opts.force: os.unlink(fn)
     36        else: sys.exit('%s exists.  --force to overwite it' % fn)
    4637
    4738try:
    48     # Initialize the diversions
    49     divs = [diversion(s, e, fn) for s, e,fn in (
    50         ('\s*-----BEGIN RSA PRIVATE KEY-----$',
    51             '\s*-----END RSA PRIVATE KEY-----$',
    52             opts.key),
    53         ('\s*-----BEGIN CERTIFICATE-----$',
    54             '\s*-----END CERTIFICATE-----$',
    55             opts.cert))]
    56 
    57     # walk through the file, beginning a diversion when a start regexp matches
    58     # until the end regexp matches.  While in the two regexps, print each line
    59     # to the ipen diversion file (including the two matches).
    60     active = None
    61     f = open(combo, 'r')
    62     for l in f:
    63         if active:
    64             if active.end.match(l):
    65                 print >>active.f, l,
    66                 active = None
    67         else:
    68             for d in divs:
    69                 if d.start.match(l):
    70                     active = d
    71                     break
    72         if active: print >>active.f, l,
    73 
    74 # This clause catches all file opening problems, including the diversion opens
     39    type = abac_pem_type(combo)
     40    if type == 'both':
     41        abac_split_cert(combo, opts.key, opts.cert)
     42    else:
     43        sys.exit('Cannot split %s as it is a %s' % (combo, type or 'dunno'));
    7544except EnvironmentError, e:
    7645    sys.exit("%s: %s" % (e.strerror, e.filename or '?!'))
    77 
    78 # This is probably unnecessary.  Close all the diversion files.
    79 for d in divs: d.f.close()
  • fedd/fedd_create.py

    r3ff5e2a r353db8c  
    66from federation.remote_service import service_caller
    77from federation.client_lib import client_opts, exit_with_fault, RPCException, \
    8         wrangle_standard_options, do_rpc, get_experiment_names, save_certfile
     8        wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,
     9        get_abac_certs
     10from federation.util import abac_split_cert
    911
    1012class fedd_create_opts(client_opts):
     
    3234                help="Explicit map from testbed label to URI - " + \
    3335                        "deter:https://users.isi.deterlab/net:13232")
     36        self.add_option('--gen_cert', action='store_true', dest='gen_cert',
     37                default=False,
     38                help='generate a cert to which to delegate rights')
     39        self.add_option('--delegate', action='store_true', dest='generate',
     40                help='Delegate rights to a generated cert (default)')
     41        self.add_option('--no-delegate', action='store_true', dest='generate',
     42                help='Do not delegate rights to a generated cert')
     43
     44        self.set_defaults('delegate'=True)
    3445
    3546def parse_service(svc):
     
    7889            }
    7990
     91def delegate(fedid, cert, dir, name=None, debug=False,
     92        creddy='/usr/local/bin/creddy'):
     93    '''
     94    Make the creddy call to create an attribute delegating rights to the new
     95    experiment.  The cert parameter points to a conventional cert & key combo,
     96    which we split out into tempfiles, which we delete on return.  The return
     97    value if the filename in which the certificate was stored.
     98    '''
     99
     100    certfile = keyfile = None
     101    expid = "%s" % fedid
     102
     103    # Trim the "fedid:"
     104    if expid.startswith("fedid:"): expid = expid[6:]
     105
     106    try:
     107        keyfile, certfile = abac_split(cert)
     108
     109        rv = 0
     110        if name: fn = '%s/%s_attr.der' % (dir, name)
     111        else: fn = '%s/%s_attr.der' % (dir, expid)
     112
     113        cmd = [creddy, '--attribute', '--issuer=%s' % certfile,
     114                '--key=%s' % keyfile,
     115                '--role=acting_for', '--subject-id=%s' % expid,
     116                '--out=%s' % fn ]
     117        if debug:
     118            print join(cmd)
     119            return fn
     120        else:
     121            if subprocess.call(cmd) == 0: return fn
     122            else: return None
     123    finally:
     124        if keyfile: os.unlink(keyfile)
     125        if certfile: os.unlink(certfile)
     126
    80127# Main line
    81128service_re = re.compile('^\\s*#\\s*SERVICE:\\s*([\\S]+)')
     
    83130(opts, args) = parser.parse_args()
    84131
    85 
     132# Option processing
    86133cert, fid, url = wrangle_standard_options(opts)
    87134
     
    97144out_certfile = opts.out_certfile
    98145
     146# If there is no abac directory in which to store a delegated credential, don't
     147# delegate.
     148if not opts.abac_dir and opts.delegate:
     149    opts.delegate = False
     150
     151# Load ABAC certs
     152if opts.abac_dir:
     153    try:
     154        acerts = get_abac_certs(opts.abac_dir)
     155    except EnvironmentError, e:
     156        sys.exit('%s: %s' % (e.filename, e.strerror))
     157
    99158# Fill in services
    100159svcs = []
     
    102161    svcs.append(project_export_service(opts.master, opts.project))
    103162svcs.extend([ parse_service(s) for s in opts.service])
     163
    104164# Parse all the strings that we can pull out of the file using the service_re.
    105165svcs.extend([parse_service(service_re.match(l).group(1)) \
     
    117177    print >>sys.stderr, "Warning:Neither master/project nor services requested"
    118178
    119 
     179# Construct the New experiment request
    120180msg = { }
     181
     182
     183# Generate a certificate if requested and put it into the message
     184if opts.gen_cert:
     185    expid, expcert = generate_fedid(opts.exp_name or 'dummy')
     186    msg['experimentAccess'] = { 'X509': expcert }
     187else:
     188    expid = expcert = None
    121189
    122190if opts.exp_name:
    123191    msg['experimentID'] = { 'localname': opts.exp_name }
    124192
     193if acerts:
     194    msg['credential'] = acerts
     195
    125196if opts.debug > 1: print >>sys.stderr, msg
    126197
     198# The New call
    127199try:
    128200    resp_dict = do_rpc(msg,
     
    138210if opts.debug > 1: print >>sys.stderr, resp_dict
    139211
     212# Save the experiment ID certificate if we need it
    140213try:
    141214    save_certfile(opts.out_certfile, resp_dict.get('experimentAccess', None))
     
    147220    e_local = "serialize"
    148221
     222# If delegation is requested and we have a target, make the delegation, and add
     223# the credential to acerts.
     224if e_fedid and opts.delegate:
     225    new_cert_fn = delegate(e_fedid, cert, key, dir, opts.exp_name)
     226    if new_cert_fn is not None:
     227        try:
     228            f = open(new_cert_fn, 'r')
     229            acerts.add(f.read())
     230            f.close()
     231        except EnvironmentError, e:
     232            sys.exit("Cannot read delegation cert in %s: %s" % \
     233                    (e.filename, e.strerror));
     234    else:
     235        sys.exit("Cannot delegate rights to new experiment: %s/%s" %\
     236                (expid, opts.exp_name))
     237
     238# Construct the Create message
    149239msg = { 'experimentdescription': { 'ns2description': exp_desc }, }
    150240
     
    159249    sys.exit("New did not return an experiment ID??")
    160250
     251if acerts:
     252    msg['credential'] = acerts
     253
    161254if tbmap:
    162255    msg['testbedmap'] = [ { 'testbed': t, 'uri': u } for t, u in tbmap.items() ]
     
    164257if opts.debug > 1: print >>sys.stderr, msg
    165258
     259# make the call
    166260try:
    167261    resp_dict = do_rpc(msg,
     
    177271if opts.debug > 1: print >>sys.stderr, resp_dict
    178272
     273# output
    179274e_fedid, e_local = get_experiment_names(resp_dict.get('experimentID', None))
    180275st = resp_dict.get('experimentStatus', None)
  • fedd/fedd_new.py

    r3ff5e2a r353db8c  
    1717        self.add_option("--experiment_name", dest="exp_name",
    1818                type="string", help="Suggested experiment name")
    19         self.add_option('--gen-cert', action='store_true', dest='gen_cert',
     19        self.add_option('--gen_cert', action='store_true', dest='gen_cert',
    2020                default=False,
    2121                help='generate a cert to which to delegate rights')
  • fedd/federation/authorizer.py

    r3ff5e2a r353db8c  
    1111from remote_service import service_caller
    1212from service_error import service_error
     13from util import abac_pem_type, abac_split_cert
    1314
    1415
     
    192193    attribute_error = authorizer_base.attribute_error
    193194    class no_file(RuntimeError): pass
    194 
    195     def __init__(self, certs=None, me=None, key=None, load=None):
     195    class bad_cert(RuntimeError): pass
     196
     197    def __init__(self, certs=None, me=None, key=None, load=None, save=None):
    196198        self.creddy = '/usr/local/bin/creddy'
    197199        self.globals = set()
    198200        self.lock = Lock()
    199201        self.me = me
    200         self.key = key
     202        self.save_dir = load or save
     203        # If the me parameter is a combination certificate, split it into the
     204        # abac_authorizer save directory (if any) for use with creddy.
     205        if abac_pem_type(self.me) == 'both':
     206            if self.save_dir:
     207                self.key, self.me = abac_split_cert(self.me,
     208                        keyfile="%s/key.pem" % self.save_dir,
     209                        certfile = "%s/cert.pem" % self.save_dir)
     210            else:
     211                raise abac_authorizer.bad_cert("Combination certificate " + \
     212                        "and nowhere to split it");
     213        else:
     214            self.key = key
    201215        self.context = ABAC.Context()
    202216        if me:
     
    216230
    217231        if load:
    218             self.save_dir = load
    219232            self.load(load)
    220         else:
    221             self.save_dir = None
    222233
    223234    @staticmethod
     
    453464                st = pickle.load(f)
    454465                f.close()
    455                 # Cpoy the useful attributes from the pickled state
     466                # Copy the useful attributes from the pickled state
    456467                for a in ('globals', 'key', 'me', 'cert', 'fedid'):
    457468                    setattr(self, a, getattr(st, a, None))
  • fedd/federation/util.py

    r3ff5e2a r353db8c  
    22
    33import re
     4import os
    45import string
    56import logging
     
    262263            return base
    263264
     265def abac_pem_type(cert):
     266    key_re = re.compile('\s*-----BEGIN RSA PRIVATE KEY-----$')
     267    cert_re = re.compile('\s*-----BEGIN CERTIFICATE-----$')
     268    type = None
     269    f = open(cert, 'r')
     270    for line in f:
     271        if key_re.match(line):
     272            if type is None: type = 'key'
     273            elif type == 'cert': type = 'both'
     274        elif cert_re.match(line):
     275            if type is None: type = 'cert'
     276            elif type == 'key': type = 'both'
     277        if type == 'both': break
     278    f.close()
     279    return type
     280
     281def abac_split_cert(cert, keyfile=None, certfile=None):
     282    """
     283    Split the certificate file in cert into a certificate file and a key file
     284    in cf and kf respectively.  The ABAC tools generally cannot handle combined
     285    certificates/keys.  If kf anc cf are given, they are used, otherwise tmp
     286    files are created.  Created tmp files must be deleted.  Problems opening or
     287    writing files will cause exceptions.
     288    """
     289    class diversion:
     290        '''
     291        Wraps up the reqular expression to start and end a diversion, as well as
     292        the open file that gets the lines.
     293        '''
     294        def __init__(self, start, end, fn):
     295            self.start = re.compile(start)
     296            self.end = re.compile(end)
     297            # Open the file securely with minimal permissions. NB file cannot
     298            # exist before this call.
     299            self.f = os.fdopen(os.open(fn,
     300                (os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_EXCL), 0600),
     301                'w')
     302
     303        def close(self):
     304            self.f.close()
     305
     306    if not keyfile:
     307        f, keyfile = mkstemp(suffix=".pem")
     308        os.close(f);
     309    if not certfile:
     310        f, certfile = mkstemp(suffix=".pem")
     311        os.close(f);
     312
     313    # Initialize the diversions
     314    divs = [diversion(s, e, fn) for s, e,fn in (
     315        ('\s*-----BEGIN RSA PRIVATE KEY-----$',
     316            '\s*-----END RSA PRIVATE KEY-----$',
     317            keyfile),
     318        ('\s*-----BEGIN CERTIFICATE-----$',
     319            '\s*-----END CERTIFICATE-----$',
     320            certfile))]
     321
     322    # walk through the file, beginning a diversion when a start regexp
     323    # matches until the end regexp matches.  While in the two regexps,
     324    # print each line to the open diversion file (including the two
     325    # matches).
     326    active = None
     327    f = open(cert, 'r')
     328    for l in f:
     329        if active:
     330            if active.end.match(l):
     331                print >>active.f, l,
     332                active = None
     333        else:
     334            for d in divs:
     335                if d.start.match(l):
     336                    active = d
     337                    break
     338        if active: print >>active.f, l,
     339
     340    # This is probably unnecessary.  Close all the diversion files.
     341    for d in divs: d.close()
     342    return keyfile, certfile
     343
    264344def find_pickle_problem(o, st=None):
    265345    """
  • fedd/init_abac_authorizer.py

    r3ff5e2a r353db8c  
    11#!/usr/local/bin/python
     2
     3import sys
    24
    35from optparse import OptionParser
     
    1618opts, args = parser.parse_args()
    1719
    18 if any([ not x for x in (opts.key, opts.cert, opts.policy, opts.out_dir)]):
     20if any([ not x for x in (opts.cert, opts.policy, opts.out_dir)]):
    1921    parser.print_help()
    2022    sys.exit(1)
    21 
    22 a = abac_authorizer(key=opts.key, me=opts.cert, certs=opts.policy)
    23 a.save(opts.out_dir)
     23try:
     24    a = abac_authorizer(key=opts.key, me=opts.cert, certs=opts.policy,
     25            save=opts.out_dir)
     26    a.save(opts.out_dir)
     27except EnvironmentError, e:
     28    sys.exit("Can't create or write %s: %s" % (e.filename, e.strerror))
     29except abac_authorizer.bad_cert, e:
     30    sys.exit("Error creating authorizer: %s" % e)
Note: See TracChangeset for help on using the changeset viewer.