Changeset 05191a6


Ignore:
Timestamp:
Dec 1, 2008 3:07:40 PM (15 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
Children:
f816079
Parents:
f069052
Message:

All services use authorizer. Global authorization file, shared routine to read simple authorization files. Fixes some more partial state errors in experiment_control.

Location:
fedd/fedd
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd/access.py

    rf069052 r05191a6  
    157157
    158158
    159         if not config.has_option("access", "project_allocation_uri"):
     159        if not config.has_option("allocate", "uri"):
    160160            self.allocate_project = \
    161161                allocate_project_local(config, auth)
  • fedd/fedd/allocate_project.py

    rf069052 r05191a6  
    4848        """
    4949
    50         self.debug = config.get("access", "debug_project", False)
    51         self.wap = config.get('access', 'wap', '/usr/testbed/sbin/wap')
    52         self.newproj = config.get('access', 'newproj',
     50        self.debug = config.get("allocate", "debug", False)
     51        self.wap = config.get('allocate', 'wap', '/usr/testbed/sbin/wap')
     52        self.newproj = config.get('allocate', 'newproj',
    5353                '/usr/testbed/sbin/newproj')
    54         self.mkproj = config.get('access', 'mkproj', '/usr/testbed/sbin/mkproj')
    55         self.rmproj = config.get('access', 'rmproj', '/usr/testbed/sbin/rmproj')
    56         self.addpubkey = config.get('access', 'addpubkey',
     54        self.mkproj = config.get('allocate', 'mkproj',
     55                '/usr/testbed/sbin/mkproj')
     56        self.rmproj = config.get('allocate', 'rmproj',
     57                '/usr/testbed/sbin/rmproj')
     58        self.addpubkey = config.get('allocate', 'addpubkey',
    5759                '/usr/testbed/sbin/taddpubkey')
    58         self.grantnodetype = config.get('access', 'grantnodetype',
     60        self.grantnodetype = config.get('allocate', 'grantnodetype',
    5961                '/usr/testbed/sbin/grantnodetype')
    60         self.confirmkey = config.get('access', 'confirmkey',
     62        self.confirmkey = config.get('allocate', 'confirmkey',
    6163                '/usr/testbed/sbin/taddpubkey')
    62         self.allocation_level = config.get("access", "allocation_level", "none")
     64        self.allocation_level = config.get("allocate", "allocation_level",
     65                "none")
    6366        self.log = logging.getLogger("fedd.allocate.local")
     67        set_log_level(config, "allocate", self.log)
     68
     69        if auth:
     70            self.auth = auth
     71        else:
     72            auth = authorizer()
     73            log.warn("[allocate] No authorizer passed in, using local one")
    6474
    6575        try:
     
    7181            self.allocation_level = self.none
    7282
    73 
    74         set_log_level(config, "access", self.log)
    75         fixed_key_db = config.get("access", "fixed_keys", None)
    76         fixed_project_db = config.get("access", "fixed_projects", None)
     83        access_db = config.get("allocate", "accessdb")
     84        if access_db:
     85            try:
     86                read_simple_accessdb(access_db, self.auth, 'allocate')
     87            except IOError, e:
     88                raise service_error(service_error.internal,
     89                        "Error reading accessDB %s: %s" % (access_db, e))
     90            except ValueError:
     91                raise service_error(service_error.internal, "%s" % e)
     92
     93
     94        fixed_key_db = config.get("allocate", "fixed_keys", None)
     95        fixed_project_db = config.get("allocate", "fixed_projects", None)
    7796        self.fixed_keys = set()
    7897        self.fixed_projects = set()
     
    129148        Req includes the project and resources as a dictionary
    130149        """
     150
     151        # Internal calls do not have a fedid parameter (i.e., local calls on
     152        # behalf of already vetted fedids)
     153        if fedid and not self.auth.check_attribute(fedid, "allocate"):
     154            self.log.debug("[allocate] Access denied (%s)" % fedid)
     155            raise service_error(service_error.access, "Access Denied")
    131156
    132157        if self.allocation_level < self.dynamic_projects:
     
    256281        cmds =  []
    257282
     283        # Internal calls do not have a fedid parameter (i.e., local calls on
     284        # behalf of already vetted fedids)
     285        if fedid and not self.auth.check_attribute(fedid, "allocate"):
     286            self.log.debug("[allocate] Access denied (%s)" % fedid)
     287            raise service_error(service_error.access, "Access Denied")
    258288        # While we should be more careful about this, for the short term, add
    259289        # the keys to the specified users.
     
    321351        similar protections for projects.
    322352        """
     353        # Internal calls do not have a fedid parameter (i.e., local calls on
     354        # behalf of already vetted fedids)
     355        if fedid and not self.auth.check_attribute(fedid, "allocate"):
     356            self.log.debug("[allocate] Access denied (%s)" % fedid)
     357            raise service_error(service_error.access, "Access Denied")
    323358
    324359        cmds = []
     
    380415        """
    381416
    382         def __init__(self, url, cert_file, cert_pwd, trusted_certs, method):
     417        def __init__(self, url, cert_file, cert_pwd, trusted_certs, auth,
     418                method):
    383419            service_caller.__init__(self, method)
    384420            self.url = url
     
    386422            self.cert_pwd = cert_pwd
    387423            self.trusted_certs = trusted_certs
    388             self.resp_name = resp_name
     424            self.request_body__name = "%sRequestBody" % method
     425            self.resp_name = "%sResponseBody" % method
     426            self.auth = auth
    389427            # Calling the proxy object directly invokes the proxy_call method,
    390428            # not the service_call method.
     
    394432        # Define the proxy, NB, the parameters to make_proxy are visible to the
    395433        # definition of proxy.
    396         def proxy_call(self, req, fedid=None):
     434        def proxy_call(self, req, fid=None):
    397435            """
    398436            Send req on to a remote project instantiator.
     
    405443                req = req[self.request_body_name]
    406444            else:
     445                print "request error"
    407446                raise service_error(service_error.req, "Bad formated request");
    408447
     
    412451                return r[self.resp_name]
    413452            else:
     453                print "response error"
    414454                raise service_error(service_error.protocol,
    415455                        "Bad proxy response")
     
    421461        """
    422462
    423         self.debug = config.get("access", "debug_project", False)
    424         self.url = config.get("access", "project_allocation_uri", "")
    425 
    426         self.cert_file = config.get("access", "cert_file", None)
    427         self.cert_pwd = config.get("access", "cert_pwd", None)
    428         self.trusted_certs = config.get("access", "trusted_certs", None)
     463        self.debug = config.get("allocate", "debug", False)
     464        self.url = config.get("allocate", "uri", "")
     465
     466        self.cert_file = config.get("allocate", "cert_file", None)
     467        self.cert_pwd = config.get("allocate", "cert_pwd", None)
     468        self.trusted_certs = config.get("allocate", "trusted_certs", None)
    429469
    430470        # Certs are promoted from the generic to the specific, so without a if
     
    457497        self.xmlrpc_services = { }
    458498        self.log = logging.getLogger("fedd.allocate.remote")
    459         set_log_level(config, "access", self.log)
     499        set_log_level(config, "allocate", self.log)
     500
     501        if auth:
     502            self.auth = auth
     503        else:
     504            auth = authorizer()
     505            log.warn("[allocate] No authorizer passed in, using local one")
    460506
    461507        # The specializations of the proxy functions
    462508        self.dynamic_project = self.proxy(self.url, self.cert_file,
    463                 self.cert_pwd, self.trusted_certs, "AllocateProject")
     509                self.cert_pwd, self.trusted_certs, self.auth,
     510                "AllocateProject")
    464511        self.static_project = self.proxy(self.url, self.cert_file,
    465                 self.cert_pwd, self.trusted_certs, "StaticProject")
     512                self.cert_pwd, self.trusted_certs, self.auth,
     513                "StaticProject")
    466514        self.release_project = self.proxy(self.url, self.cert_file,
    467                 self.cert_pwd, self.trusted_certs, "ReleaseProject")
    468 
     515                self.cert_pwd, self.trusted_certs, self.auth,
     516                "ReleaseProject")
     517
  • fedd/fedd/authorizer.py

    rf069052 r05191a6  
    1414    def __init__(self, def_attr="testbed"):
    1515        self.attrs = { }
     16        self.globals=set()
    1617
    1718    @staticmethod
     
    8687    def check_attribute(self, name, attr):
    8788        """
    88         Return True if name has attr.  Tuple names match any tuple name that
    89         matches all names present and has None entries in other fileds.  For
    90         tuple names True implies that there is a matching tuple name with the
    91         attribute.
     89        Return True if name has attr (or if attr is global).  Tuple names match
     90        any tuple name that matches all names present and has None entries in
     91        other fileds.  For tuple names True implies that there is a matching
     92        tuple name with the attribute.
    9293        """
    9394        def tup(tup, i, p):
     
    9798
    9899        self.valid_name(name)
     100        if attr in self.globals:
     101            return True
    99102
    100103        if isinstance(name, tuple):
     
    107110            return  attr in self.attrs.get(self.auth_name(name), set())
    108111
     112    def set_global_attribute(self, attr):
     113        """
     114        Set a global attribute.  All names, even those otherwise unknown to the
     115        authorizer have this attribute.
     116        """
     117        self.globals.add(attr)
    109118
     119    def unset_global_attribute(self, attr):
     120        """
     121        Remove a global attribute
     122        """
     123
     124        self.globals.discard(attr)
     125
  • fedd/fedd/deter_impl.py

    rf069052 r05191a6  
    44from experiment_control import experiment_control_local
    55from split import split_local
     6from util import read_simple_accessdb
    67
    78from authorizer import authorizer
     
    3233            self.trusted_certs = config.get("globals", "trusted_certs");
    3334
     35            access_db = config.get("globals", "accessdb")
     36
     37            if access_db:
     38                try:
     39                    read_simple_accessdb(access_db, self.auth)
     40                except IOError, e:
     41                    raise service_error(service_error.internal,
     42                            "Error reading accessDB %s: %s" % (access_db, e))
     43                except ValueError:
     44                    raise service_error(service_error.internal, "%s" % e)
     45
    3446            if config.has_section("access"):
    3547                self.access = access(config, self.auth)
  • fedd/fedd/experiment_control.py

    rf069052 r05191a6  
    15371537            self.state_lock.release()
    15381538
    1539         try:
    1540             self.generate_ssh_keys(gw_secretkey, self.ssh_type)
    1541         except ValueError:
    1542             raise service_error(service_error.server_config,
    1543                     "Bad key type (%s)" % self.ssh_type)
    1544 
    1545         user = req.get('user', None)
    1546         if user == None:
    1547             raise service_error(service_error.req, "No user")
    1548 
    1549         master = req.get('master', None)
    1550         if not master:
    1551             raise service_error(service_error.req, "No master testbed label")
    1552         export_project = req.get('exportProject', None)
    1553         if not export_project:
    1554             raise service_error(service_error.req, "No export project")
    1555        
    1556         if self.splitter_url:
    1557             self.log.debug("Calling remote splitter at %s" % self.splitter_url)
    1558             split_data = self.remote_splitter(self.splitter_url, file_content,
    1559                     master)
    1560         else:
    1561             tclcmd = [self.tclsh, self.tcl_splitter, '-s', '-x',
    1562                 str(self.muxmax), '-m', master]
    1563 
    1564             if self.fedkit:
    1565                 tclcmd.append('-k')
    1566 
    1567             tclcmd.extend([pid, gid, eid, tclfile])
    1568 
    1569             self.log.debug("running local splitter %s", " ".join(tclcmd))
    1570             tclparser = Popen(tclcmd, stdout=PIPE)
    1571             split_data = tclparser.stdout
    1572 
    1573         allocated = { }     # Testbeds we can access
    1574         started = { }       # Testbeds where a sub-experiment started
    1575                             # successfully
    1576 
    1577         # Objects to parse the splitter output (defined above)
    1578         parse_current_testbed = self.current_testbed(eid, tmpdir, self.fedkit)
    1579         parse_allbeds = self.allbeds(self.get_access)
    1580         parse_gateways = self.gateways(eid, master, tmpdir,
    1581                 gw_pubkey_base, gw_secretkey_base, self.copy_file, self.fedkit)
    1582         parse_vtopo = self.shunt_to_string("^#\s+Begin\s+Vtopo",
    1583                     "^#\s+End\s+Vtopo")
    1584         parse_hostnames = self.shunt_to_file("^#\s+Begin\s+hostnames",
    1585                     "^#\s+End\s+hostnames", tmpdir + "/hosts")
    1586         parse_tarfiles = self.shunt_to_list("^#\s+Begin\s+tarfiles",
    1587                 "^#\s+End\s+tarfiles")
    1588         parse_rpms = self.shunt_to_list("^#\s+Begin\s+rpms",
    1589                 "^#\s+End\s+rpms")
    1590 
    15911539        try:
     1540            # This catches exceptions to clear the placeholder if necessary
     1541            try:
     1542                self.generate_ssh_keys(gw_secretkey, self.ssh_type)
     1543            except ValueError:
     1544                raise service_error(service_error.server_config,
     1545                        "Bad key type (%s)" % self.ssh_type)
     1546
     1547            user = req.get('user', None)
     1548            if user == None:
     1549                raise service_error(service_error.req, "No user")
     1550
     1551            master = req.get('master', None)
     1552            if not master:
     1553                raise service_error(service_error.req,
     1554                        "No master testbed label")
     1555            export_project = req.get('exportProject', None)
     1556            if not export_project:
     1557                raise service_error(service_error.req, "No export project")
     1558           
     1559            if self.splitter_url:
     1560                self.log.debug("Calling remote splitter at %s" % \
     1561                        self.splitter_url)
     1562                split_data = self.remote_splitter(self.splitter_url,
     1563                        file_content, master)
     1564            else:
     1565                tclcmd = [self.tclsh, self.tcl_splitter, '-s', '-x',
     1566                    str(self.muxmax), '-m', master]
     1567
     1568                if self.fedkit:
     1569                    tclcmd.append('-k')
     1570
     1571                tclcmd.extend([pid, gid, eid, tclfile])
     1572
     1573                self.log.debug("running local splitter %s", " ".join(tclcmd))
     1574                tclparser = Popen(tclcmd, stdout=PIPE)
     1575                split_data = tclparser.stdout
     1576
     1577            allocated = { }         # Testbeds we can access
     1578            started = { }           # Testbeds where a sub-experiment started
     1579                                # successfully
     1580
     1581            # Objects to parse the splitter output (defined above)
     1582            parse_current_testbed = self.current_testbed(eid, tmpdir,
     1583                    self.fedkit)
     1584            parse_allbeds = self.allbeds(self.get_access)
     1585            parse_gateways = self.gateways(eid, master, tmpdir,
     1586                    gw_pubkey_base, gw_secretkey_base, self.copy_file,
     1587                    self.fedkit)
     1588            parse_vtopo = self.shunt_to_string("^#\s+Begin\s+Vtopo",
     1589                        "^#\s+End\s+Vtopo")
     1590            parse_hostnames = self.shunt_to_file("^#\s+Begin\s+hostnames",
     1591                        "^#\s+End\s+hostnames", tmpdir + "/hosts")
     1592            parse_tarfiles = self.shunt_to_list("^#\s+Begin\s+tarfiles",
     1593                    "^#\s+End\s+tarfiles")
     1594            parse_rpms = self.shunt_to_list("^#\s+Begin\s+rpms",
     1595                    "^#\s+End\s+rpms")
     1596
    15921597            # Working on the split data
    15931598            for line in split_data:
     
    16111616                    raise service_error(service_error.internal,
    16121617                            "Bad tcl parse? %s" % line)
     1618            # Virtual topology and visualization
     1619            vtopo = self.gentopo(parse_vtopo.str)
     1620            if not vtopo:
     1621                raise service_error(service_error.internal,
     1622                        "Failed to generate virtual topology")
     1623
     1624            vis = self.genviz(vtopo)
     1625            if not vis:
     1626                raise service_error(service_error.internal,
     1627                        "Failed to generate visualization")
     1628           
     1629            # save federant information
     1630            for k in allocated.keys():
     1631                tbparams[k]['federant'] = {\
     1632                        'name': [ { 'localname' : eid} ],\
     1633                        'emulab': tbparams[k]['emulab'],\
     1634                        'allocID' : tbparams[k]['allocID'],\
     1635                        'master' : k == master,\
     1636                    }
     1637
     1638
     1639            # Copy tarfiles and rpms needed at remote sites into a staging area
     1640            try:
     1641                if self.fedkit:
     1642                    parse_tarfiles.list.append(self.fedkit)
     1643                for t in parse_tarfiles.list:
     1644                    if not os.path.exists("%s/tarfiles" % tmpdir):
     1645                        os.mkdir("%s/tarfiles" % tmpdir)
     1646                    self.copy_file(t, "%s/tarfiles/%s" % \
     1647                            (tmpdir, os.path.basename(t)))
     1648                for r in parse_rpms.list:
     1649                    if not os.path.exists("%s/rpms" % tmpdir):
     1650                        os.mkdir("%s/rpms" % tmpdir)
     1651                    self.copy_file(r, "%s/rpms/%s" % \
     1652                            (tmpdir, os.path.basename(r)))
     1653            except IOError, e:
     1654                raise service_error(service_error.internal,
     1655                        "Cannot stage tarfile/rpm: %s" % e.strerror)
     1656
    16131657        except service_error, e:
    16141658            # If something goes wrong in the parse (usually an access error)
    1615             # clear the placeholder state
     1659            # clear the placeholder state.  From here on out the code delays
     1660            # exceptions.
    16161661            self.state_lock.acquire()
    16171662            del self.state[eid]
    16181663            self.state_lock.release()
    16191664            raise e
    1620        
    1621         # Virtual topology and visualization
    1622         vtopo = self.gentopo(parse_vtopo.str)
    1623         if not vtopo:
    1624             raise service_error(service_error.internal,
    1625                     "Failed to generate virtual topology")
    1626 
    1627         vis = self.genviz(vtopo)
    1628         if not vis:
    1629             raise service_error(service_error.internal,
    1630                     "Failed to generate visualization")
    1631 
    1632         # save federant information
    1633         for k in allocated.keys():
    1634             tbparams[k]['federant'] = {\
    1635                     'name': [ { 'localname' : eid} ],\
    1636                     'emulab': tbparams[k]['emulab'],\
    1637                     'allocID' : tbparams[k]['allocID'],\
    1638                     'master' : k == master,\
    1639                 }
    1640 
    1641 
    1642         # Copy tarfiles and rpms needed at remote sites into a staging area
    1643         try:
    1644             if self.fedkit:
    1645                 parse_tarfiles.list.append(self.fedkit)
    1646             for t in parse_tarfiles.list:
    1647                 if not os.path.exists("%s/tarfiles" % tmpdir):
    1648                     os.mkdir("%s/tarfiles" % tmpdir)
    1649                 self.copy_file(t, "%s/tarfiles/%s" % \
    1650                         (tmpdir, os.path.basename(t)))
    1651             for r in parse_rpms.list:
    1652                 if not os.path.exists("%s/rpms" % tmpdir):
    1653                     os.mkdir("%s/rpms" % tmpdir)
    1654                 self.copy_file(r, "%s/rpms/%s" % \
    1655                         (tmpdir, os.path.basename(r)))
    1656         except IOError, e:
    1657             raise service_error(service_error.internal,
    1658                     "Cannot stage tarfile/rpm: %s" % e.strerror)
    16591665
    16601666        thread_pool_info = self.thread_pool()
  • fedd/fedd/remote_service.py

    rf069052 r05191a6  
    227227        resp = self.constructor()
    228228        set_element = getattr(resp, "set_element_%s" % self.body_name, None)
    229         print "set_element_%s" % self.body_name
    230229        if set_element and callable(set_element):
    231230            try:
  • fedd/fedd/server.py

    rf069052 r05191a6  
    4040        self.log = logging.getLogger("fedd")
    4141
    42     def handle_error(self, request, address):
     42    def ahandle_error(self, request, address):
    4343        """
    4444        The default SSLServer prints a stack trace here.  This is a little
  • fedd/fedd/split.py

    rf069052 r05191a6  
    1010from remote_service import xmlrpc_handler, soap_handler
    1111from service_error import *
     12from authorizer import authorizer
    1213
    1314
     
    2324        Intialize the various attributes, most from the config object
    2425        """
    25         if config.has_section("splitter"):
    26             self.debug = config.getboolean("splitter", "debug")
    27             self.muxmax = config.getint("splitter", "muxmax", 3)
    28             self.tclsh = config.get("splitter", "tclsh",
    29                     "/usr/local/bin/otclsh")
    30             self.tcl_splitter = config.get("splitter", "tcl_splitter",
    31                     "/usr/testbed/lib/ns2ir/parse.tcl")
    32         else:
    33             self.debug = False
    34             self.muxmax = 3
    35             self.tclsh = "/usr/local/bin/otclsh"
    36             self.tcl_splitter = "/usr/testbed/lib/ns2ir/parse.tcl"
     26        self.debug = config.getboolean("splitter", "debug")
     27        self.muxmax = config.getint("splitter", "muxmax", 3)
     28        self.tclsh = config.get("splitter", "tclsh",
     29                "/usr/local/bin/otclsh")
     30        self.tcl_splitter = config.get("splitter", "tcl_splitter",
     31                "/usr/testbed/lib/ns2ir/parse.tcl")
     32        access_db = config.get("splitter", "access_db", None)
     33        allow_any = config.getboolean("splitter", "allow_any", False)
    3734
    3835        self.log = logging.getLogger("fedd.splitter")
     
    4138
    4239        set_log_level(config, "splitter", self.log)
     40
     41        if auth:
     42            self.auth= auth
     43        else:
     44            self.auth = authorizer()
     45            self.log.warning("[splitter] No authorizer passed in, " +\
     46                    "using local one")
     47
     48        if access_db and allow_any:
     49            raise service_error(service_error.internal,
     50                    "Cannot specify both an access database and allow_any " +\
     51                            "for splitter")
     52       
     53        if access_db:
     54            try:
     55                read_simple_accessdb(access_db, self.auth, 'split')
     56            except IOError, e:
     57                raise service_error(service_error.internal,
     58                        "Error reading accessDB %s: %s" % (access_db, e))
     59            except ValueError:
     60                raise service_error(service_error.internal, "%s" % e)
     61        elif allow_any:
     62            auth.set_global_attribute("split")
     63
     64
    4365        # Dispatch tables
    4466        self.soap_services = {\
     
    6082        to instantiate them and start it all up.
    6183        """
     84
     85        if not self.auth.check_attribute(fid, 'split'):
     86            raise service_error(service_error.access, "Access Denied")
     87
    6288        try:
    6389            tmpdir = tempfile.mkdtemp(prefix="split-")
  • fedd/fedd/util.py

    rf069052 r05191a6  
    11#!/usr/local/bin/python
    22
     3import re
     4import string
    35import logging
    46
     
    4446                callback=SSL.cb.ssl_verify_callback_allow_unknown_ca)
    4547
     48def read_simple_accessdb(fn, auth, mask=[]):
     49    """
     50    Read a simple access database.  Each line is a fedid (of the form
     51    fedid:hexstring) and a comma separated list of atributes to be assigned to
     52    it.  This parses out the fedids and adds the attributes to the authorizer.
     53    comments (preceded with a #) and blank lines are ignored.  Exceptions (e.g.
     54    file exceptions and ValueErrors from badly parsed lines) are propagated.
     55    """
     56
     57    rv = [ ]
     58    lineno = 0
     59    fedid_line = re.compile("fedid:([" + string.hexdigits + "]+)\s+" +\
     60            "(\w+\s*(,\s*\w+)*)")
     61
     62    # If a single string came in, make it a list
     63    if isinstance(mask, basestring): mask = [ mask ]
     64
     65    f = open(fn, 'r')
     66    for line in f:
     67        lineno += 1
     68        line = line.strip()
     69        if line.startswith('#') or len(line) == 0:
     70            continue
     71        m = fedid_line.match(line)
     72        if m :
     73            fid = fedid(hexstr=m.group(1))
     74            for a in [ a.strip() for a in m.group(2).split(",") \
     75                    if not mask or a.strip() in mask ]:
     76                auth.set_attribute(fid, a.strip())
     77        else:
     78            raise ValueError("Badly formatted line in accessdb: %s line %d" %\
     79                    (nf, lineno))
     80    f.close()
     81    return rv
     82       
     83
    4684def pack_id(id):
    4785    """
Note: See TracChangeset for help on using the changeset viewer.