Changeset 5c0d244


Ignore:
Timestamp:
Sep 13, 2010 9:51:13 AM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
9cce15a
Parents:
49e66b4
Message:

Beginnings of an ABAC authorizer

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/authorizer.py

    r49e66b4 r5c0d244  
    11#/usr/local/bin/python
    22
     3from tempfile import mkstemp
     4from subprocess import call
    35from fedid import fedid
    46from remote_service import service_caller
     
    68from service_error import service_error
    79
     10import ABAC
     11import pickle
     12
    813import sys
     14import os
    915
    1016class authorizer_base:
     
    1723    # general error exception for badly formed names. 
    1824    class bad_name(RuntimeError): pass
     25    # difficulty creating an attribute
     26    class attribute_error(RuntimeError): pass
    1927
    2028    @staticmethod
     
    146154        return rv
    147155
     156    def clone(self):
     157        rv = authorizer()
     158        rv.attrs = self.attrs.copy()
     159        rv.globals = self.globals.copy()
     160        return rv
     161
     162    def save(self, fn):
     163        f = open(fn, "w")
     164        pickle.dump(self, f)
     165        f.close()
     166
     167    def load(self, fn):
     168        f = open(fn, "r")
     169        a = pickle.load(f)
     170        f.close()
     171        self.attrs = a.attrs
     172        self.globals = a.globals
     173       
     174
    148175class abac_authorizer(authorizer_base):
    149176    """
     
    151178    """
    152179
    153     def __init__(self, url=None, cert_file=None, cert_pwd=None,
    154             trusted_certs=None, me=None):
    155         self.call_CreateContext = abac_service_caller('CreateContext')
    156         self.call_CredentialUpdate = abac_service_caller('CredentialUpdate')
    157         self.call_Access = abac_service_caller('Access')
     180    def __init__(self, certs=None, me=None, key=None, from_dir=None):
     181        self.bad_name = authorizer_base.bad_name
     182        self.attribute_error = authorizer_base.attribute_error
    158183        self.globals = set()
    159 
    160         self.url = url
    161         self.cert_file = cert_file
    162         self.cert_pwd = cert_pwd
    163         self.trusted_certs = trusted_certs
     184        self.creddy = '/usr/local/bin/creddy'
    164185        self.me = me
    165         req = { 'context': { 'self': me.get_hexstr()} }
    166         # May throw a service error
    167         resp = self.call_CreateContext(self.url, req, self.cert_file,
    168                 self.cert_pwd, self.trusted_certs, tracefile=sys.stderr)
    169 
    170         if resp.has_key('CreateContextResponseBody'):
    171             resp =  resp['CreateContextResponseBody']
    172             if resp.has_key('contextID'):
    173                 self.contextID = resp['contextID']
     186        self.my_key = key
     187        self.context = ABAC.Context()
     188        for dir in certs or []:
     189            self.context.load_directory(dir)
     190
     191    def set_attribute(self, name=None, attr=None, cert=None):
     192        if name and attr:
     193            if isinstance(name, tuple):
     194                raise self.bad_name("ABAC doesn't understand three-names")
     195            if self.me and self.key:
     196                # Create a credential and insert it into context
     197                # This will simplify when we have libcreddy
     198                try:
     199                    # create temp file
     200                    f, fn = mkstemp()
     201                    f.close()
     202                except EnvironmentError, e:
     203                    raise self.attribute_error(
     204                            "Cannot create temp file: %s" %e)
     205
     206                # Create the attribute certificate with creddy
     207                rv = call([creddy, '--attribute', '--issuer=%s' % self.me,
     208                    '--key=%s' % self.key, '--role=%s' % attr,
     209                    '--subject-id=%s' % name, '--out=%s' % fn])
     210                if rv == 0:
     211                    # load it to context and remove the file
     212                    self.context.load_attribute(fn)
     213                    os.unlink(fn)
     214                else:
     215                    os.unlink(fn)
     216                    raise self.attribute_error("creddy returned %s" % rv)
    174217            else:
    175                 raise service_error(service_error.internal,
    176                         "No context ID for the new authorization context")
    177         else:
    178             raise service_error(service_error.internal,
    179                     "Bad response to creating service context")
    180 
    181     def set_attribute(self, name, attr):
    182         self.valid_name(name)
     218                raise self.attribute_error(
     219                        "Identity and key not specified on creation")
     220        elif cert:
     221            # Insert this credential into the context
     222            self.context.load_attribute_chunk(cert)
     223        else:
     224            raise self.attribute_error("Neither name/attr nor cert is set")
     225
     226    def check_attribute(self, name, attr):
     227        # XXX proof soon
    183228        if isinstance(name, tuple):
    184             if not isinstance(name[0], fedid):
    185                 raise service_error(service_error.internal,
    186                         "Triple not anchored in testbed")
    187             if not name[1] and not name[2]:
    188                 raise service_error(service_error.internal,
    189                         "Anonymous access not yet permitted")
    190 
    191             preconditions = "^".join(
    192                     [ "%s.%s" % (name[0], self.auth_name(n)) \
    193                             for n in name[1:3] if n ])
    194 
    195             req = {
    196                     'credential': [ '%s.%s<--%s' % \
    197                             ( self.me, attr, preconditions) ],
    198                     'context': { 'contextID': self.contextID  }
    199                 }
    200         else:
    201             req = {
    202                     'credential': [ '%s.%s<--%s' % \
    203                             ( self.me, attr, self.auth_name(name)) ],
    204                     'context': { 'contextID': self.contextID }
    205                 }
    206         print req
    207         self.call_CredentialUpdate(self.url, req, self.cert_file,
    208                 self.cert_pwd, self.trusted_certs, tracefile=sys.stderr)
    209 
    210     def check_attribute(self, name, attr):
    211         self.valid_name(name)
    212         if attr in self.globals: return True
    213 
    214         if isinstance(name, tuple):
    215             raise service_error(service_error.internal,
    216                     "Only fedids permitted here")
    217         req = {
    218                 'goal': '%s:%s<<---%s' % (self.me, attr, name),
    219                 'context': { 'contextID': self.contextID }
    220             }
    221         resp = self.call_Access(self.url, req, self.cert_file, self.cert_pwd,
    222                 self.trusted_certs)
    223         if resp.has_key('AccessResponseBody'):
    224             resp = resp['AccessResponseBody']
    225 
    226         result = resp.get('result', None)
    227         return (result and result.lower() == 'true')
     229            raise self.bad_name("ABAC doesn't understand three-names")
     230        else:
     231            proof, rv = self.context.query(attr, name)
     232            # XXX delete soon
     233            if not rv and attr in self.globals: return True
     234            else: return rv
    228235
    229236    def set_global_attribute(self, attr):
     
    241248        self.globals.discard(attr)
    242249
     250    def clone(self):
     251        rv = abac_authorizer(me=self.me, key=self.key)
     252        rv.globals = self.globals.copy()
     253        rv.context = ABAC.Context(self.context)
     254        return rv
     255
     256    def save(self, dir):
     257        os.mkdir(dir)
     258
     259        f = open("%s/globals" % dir, "w")
     260        pickle.dump(self.globals, f)
     261        f.close()
     262
     263        if self.me and self.key:
     264            f = open("%s/me" % dir, "w")
     265            pickle.dump(self.me, f)
     266            f.close()
     267            f = open("%s/key" % dir, "w")
     268            pickle.dump(self.key, f)
     269            f.close()
     270        os.mkdir("%s/certs" % dir)
     271        seenit = set()
     272        ii = 0
     273        ai = 0
     274        for c in self.context.credentials():
     275            id = c.issuer_cert()
     276            attr = c.attribute_cert()
     277            if id not in seenit:
     278                f = open("%s/certs/%03d_ID.der" % (dir, ii), "w")
     279                print >>f, id
     280                f.close()
     281                ii += 1
     282                seenit.add(id)
     283            if attr:
     284                f = open("%s/certs/%03d_attr.der" % (dir, ai), "w")
     285                print >>f, attr
     286                f.close()
     287                ai += 1
     288
     289    def load(self, dir):
     290        if os.access("%s/me" % dir, os.R_OK):
     291            f = open("%s/me" % dir, "r")
     292            self.me = pickle.load(f)
     293            f.close()
     294        else:
     295            self.me = None
     296        if os.access("%s/key" % dir, os.R_OK):
     297            f = open("%s/key" % dir, "r")
     298            self.key = pickle.load(f)
     299            f.close()
     300        else:
     301            self.key = None
     302        f = open("%s/globals" % dir, "r")
     303        self.globals = pickle.load(f)
     304        f.close()
     305        self.context = ABAC.context()
     306        self.context.load_directory("%s/certs" % dir)
     307
Note: See TracChangeset for help on using the changeset viewer.