Changeset dee164e


Ignore:
Timestamp:
Nov 30, 2010 7:20:16 PM (13 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
c324ad3
Parents:
4692a16
Message:

Looks like internal works now.

Had to add default entries to the access list to accomodate that, and discovered that ABAC requires strings - not unicode.

Moved lookup_access into the aceess class as most should be able to use it directly now.

Location:
fedd/federation
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/access.py

    r4692a16 rdee164e  
    132132
    133133
    134     def read_access(self, fn, access_obj=None):
     134    def read_access(self, fn, access_obj=None, default=[]):
    135135        """
    136136        Read an access DB of the form
     
    188188            if a.attr in priorities:
    189189                a.priority = priorities[a.attr]
     190
     191        # default access mappings
     192        for a, v in default:
     193            self.access.append(
     194                    access_base.access_attribute(attr=a, value=v, pri=0))
     195
     196
    190197
    191198    def write_state(self):
     
    226233                self.log.warning(("[read_state]: No saved state: " + \
    227234                        "Unpickling failed: %s") % e)
     235
     236    def lookup_access(self, req, fid, filter=None, compare=None):
     237        """
     238        Check all the attributes that this controller knows how to map and see
     239        if the requester is allowed to use any of them.  If so return one.
     240        Filter defined the objects to check - it's a function that returns true
     241        for the objects to check - and cmp defines the order to check them in
     242        as the cmp field of sorted().  If filter is None, all possibilities are
     243        checked.  If cmp is None, the choices are sorted by priority.
     244        """
     245
     246        # Import request credentials into this (clone later??)
     247        if self.auth.import_credentials(
     248                data_list=req.get('abac_credential', [])):
     249            self.auth.save()
     250
     251        # NB: in the default case (the else), the comparison order is reversed
     252        # so numerically larger priorities are checked first.
     253        if compare: c = compare
     254        else: c = lambda(a, b): cmp(b,a)
     255
     256        if filter: f = filter
     257        else: f = lambda(x): True
     258
     259        check = sorted([ a for a in self.access if f(a)], cmp=c)
     260
     261        # Check every attribute that we know how to map and take the first
     262        # success.
     263        for attr in check:
     264            if self.auth.check_attribute(fid, attr.attr):
     265                self.log.debug("Access succeeded for %s %s" % (attr.attr, fid))
     266                # XXX: needs to deal with dynamics
     267                return copy.copy(attr.value), (False, False, False), \
     268                        [ fid ]
     269            else:
     270                self.log.debug("Access failed for %s %s" % (attr.attr, fid))
     271        else:
     272            raise service_error(service_error.access, "Access denied")
     273
    228274
    229275
  • fedd/federation/authorizer.py

    r4692a16 rdee164e  
    66from threading import Lock
    77
    8 from string import join
     8from string import join, hexdigits
    99
    1010from fedid import fedid
     
    240240        return abac_authorizer.clean_attr_re.sub('_', attr)
    241241
     242
    242243    def import_credentials(self, file_list=None, data_list=None):
    243244        if data_list:
     
    272273            if not isinstance(attr, basestring):
    273274                attr = "%s" % attr
     275
    274276            if self.me and self.key:
    275277                # Create a credential and insert it into context
     
    338340        self.lock.release()
    339341
     342    @staticmethod
     343    def starts_with_fedid(attr):
     344        """
     345        Return true if the first 40 characters of the string are hex digits
     346        followed by a dot.  False otherwise.  Used in check_attribute.
     347        """
     348        if attr.find('.') == 40:
     349            return all([ x in hexdigits for x in attr[0:40]])
     350        else:
     351            return False
     352
    340353
    341354    def check_attribute(self, name, attr):
     
    348361            if not isinstance(attr, basestring):
    349362                attr = "%s" % attr
    350             # Naked attributes are attested by this principal
    351             if attr.find('.') == -1:
    352                 a = "%s.%s" % (self.fedid, self.clean_attr(attr))
    353             else:
     363            # Attributes that start with a fedid only have the part of the
     364            # attribute after the dot cleaned.  Others are completely cleaned
     365            # and have the owner fedid attached.
     366            if self.starts_with_fedid(attr):
    354367                r, a = attr.split('.',1)
    355368                a = "%s.%s" % ( r, self.clean_attr(a))
     369            else:
     370                a = "%s.%s" % (self.fedid, self.clean_attr(attr))
     371
     372            a = str(a)
     373            n = str("%s" % name)
    356374
    357375            self.lock.acquire()
    358             rv, proof = self.context.query(a, "%s" % name)
     376            # Sigh. Unicode vs swig and swig seems to lose.  Make sure
     377            # everything we pass into ABAC is a str not a unicode.
     378            rv, proof = self.context.query(a, n)
    359379            # XXX delete soon
    360380            if not rv and attr in self.globals: rv = True
  • fedd/federation/deter_internal_access.py

    r4692a16 rdee164e  
    1515from allocate_project import allocate_project_local, allocate_project_remote
    1616from fedid import fedid, generate_fedid
    17 from authorizer import authorizer
     17from authorizer import authorizer, abac_authorizer
    1818from service_error import service_error
    1919from remote_service import xmlrpc_handler, soap_handler, service_caller
     
    2929
    3030from access import access_base
     31from legacy_access import legacy_access
    3132
    3233# Make log messages disappear if noone configures a fedd logger
     
    3738fl.addHandler(nullHandler())
    3839
    39 class access(access_base):
     40class access(access_base, legacy_access):
    4041    @staticmethod
    4142    def parse_vlans(v, log=None):
     
    8182        set_log_level(config, "access", self.log)
    8283
    83         if config.has_option("access", "accessdb"):
    84             self.read_access(config.get("access", "accessdb"))
    85 
    86         # Add the ownership attributes to the authorizer.  Note that the
    87         # indices of the allocation dict are strings, but the attributes are
    88         # fedids, so there is a conversion.
    89         self.state_lock.acquire()
    90         for k in self.state.keys():
    91             for o in self.state[k].get('owners', []):
    92                 self.auth.set_attribute(o, fedid(hexstr=k))
    93             self.auth.set_attribute(fedid(hexstr=k),fedid(hexstr=k))
    94             # If the allocation has a vlan assigned, remove it from the
    95             # available vlans
    96             v = self.state[k].get('vlan', None)
    97             if v:
    98                 self.vlans.discard(v)
    99         self.state_lock.release()
    100 
    101         self.lookup_access = self.lookup_access_base
     84
     85        # authorization information
     86        self.auth_type = config.get('access', 'auth_type') \
     87                or 'legacy'
     88        self.auth_dir = config.get('access', 'auth_dir')
     89        accessdb = config.get("access", "accessdb")
     90        # initialize the authorization system
     91        if self.auth_type == 'legacy':
     92            self.access = { }
     93            if accessdb:
     94                self.legacy_read_access(accessdb)
     95        elif self.auth_type == 'abac':
     96            self.auth = abac_authorizer(load=self.auth_dir)
     97            self.access = [ ]
     98            if accessdb:
     99                self.read_access(accessdb, default=[('access', None)])
     100        else:
     101            raise service_error(service_error.internal,
     102                    "Unknown auth_type: %s" % self.auth_type)
     103
     104        if self.auth_type == 'legacy':
     105            # Add the ownership attributes to the authorizer.  Note that the
     106            # indices of the allocation dict are strings, but the attributes are
     107            # fedids, so there is a conversion.
     108            self.state_lock.acquire()
     109            for k in self.state.keys():
     110                for o in self.state[k].get('owners', []):
     111                    self.auth.set_attribute(o, fedid(hexstr=k))
     112                self.auth.set_attribute(fedid(hexstr=k),fedid(hexstr=k))
     113                # If the allocation has a vlan assigned, remove it from the
     114                # available vlans
     115                v = self.state[k].get('vlan', None)
     116                if v:
     117                    self.vlans.discard(v)
     118            self.state_lock.release()
     119
     120            self.lookup_access = self.legacy_lookup_access_base
     121        # under ABAC we use access.lookup_access
     122
    102123
    103124        self.call_GetValue= service_caller('GetValue')
     
    135156            raise service_error(service_error.req, "No request!?")
    136157
    137         found, match = self.lookup_access(req, fid)
     158        found, match, owners = self.lookup_access(req, fid)
    138159        # keep track of what's been added
    139160        allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
     
    143164        self.state[aid] = { }
    144165        self.state[aid]['user'] = found
    145         self.state[aid]['owners'] = [ fid ]
     166        self.state[aid]['owners'] = owners
    146167        self.state[aid]['vlan'] = None
    147168        self.write_state()
     
    149170        self.auth.set_attribute(fid, allocID)
    150171        self.auth.set_attribute(allocID, allocID)
     172        self.auth.save()
    151173
    152174        try:
  • fedd/federation/emulab_access.py

    r4692a16 rdee164e  
    328328                [ fid ]
    329329
    330     def lookup_access(self, req, fid, filter=None, compare=None):
    331         """
    332         Check all the attributes that this controller knows how to map and see
    333         if the requester is allowed to use any of them.  If so return one.
    334         Filter defined the objects to check - it's a function that returns true
    335         for the objects to check - and cmp defines the order to check them in
    336         as the cmp field of sorted().  If filter is None, all possibilities are
    337         checked.  If cmp is None, the choices are sorted by priority.
    338         """
    339 
    340         # Import request credentials into this (clone later??)
    341         if self.auth.import_credentials(
    342                 data_list=req.get('abac_credential', [])):
    343             self.auth.save()
    344 
    345         # NB: in the default case (the else), the comparison order is reversed
    346         # so numerically larger priorities are checked first.
    347         if compare: c = compare
    348         else: c = lambda(a, b): cmp(b,a)
    349 
    350         if filter: f = filter
    351         else: f = lambda(x): True
    352 
    353         check = sorted([ a for a in self.access if f(a)], cmp=c)
    354 
    355         # Check every attribute that we know how to map and take the first
    356         # success.
    357         for attr in check:
    358             if self.auth.check_attribute(fid, attr.attr):
    359                 self.log.debug("Access succeeded for %s %s" % (attr.attr, fid))
    360                 # XXX: needs to deal with dynamics
    361                 return copy.copy(attr.value), (False, False, False), \
    362                         [ fid ]
    363             else:
    364                 self.log.debug("Access failed for %s %s" % (attr.attr, fid))
    365         else:
    366             raise service_error(service_error.access, "Access denied")
    367 
    368 
    369330    def do_project_allocation(self, dyn, project, user):
    370331        """
  • fedd/federation/experiment_control.py

    r4692a16 rdee164e  
    19991999            for tb in [ t for t in topo if t not in allocated]:
    20002000                #XXX: ABAC
    2001                 self.get_access(tb, None, tbparams, access_user, masters, tbmap)
     2001                if self.auth_type =='legacy':
     2002                    self.get_access(tb, None, tbparams, access_user,
     2003                            masters, tbmap)
     2004                elif self.auth_type == 'abac':
     2005                    self.get_abac_access(tb, tbparams, fid, masters, tbmap,
     2006                            expid, expcert_file)
     2007                else:
     2008                    raise service_error(service_error.internal,
     2009                            "Unknown auth_type %s" % self.auth_type)
    20022010                allocated[tb] = 1
    20032011                store_keys = topo[tb].get_attribute('store_keys')
     
    20442052            if self.state_filename: self.write_state()
    20452053            self.state_lock.release()
     2054            if tmpdir and self.cleanup:
     2055                self.remove_dirs(tmpdir)
    20462056            raise e
    20472057
Note: See TracChangeset for help on using the changeset viewer.