source: tools/policy/policy.py @ e69367b

gec13
Last change on this file since e69367b was 3821a93, checked in by Ted Faber <faber@…>, 12 years ago

List Principals who can perform actions

  • Property mode set to 100644
File size: 7.6 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4import os
5import os.path
6import re
7
8import ABAC
9import Creddy
10import zipfile
11import tempfile
12from util import *
13
14class policy:
15    def __init__(self):
16        self.translate = 'keyids'
17        self.clear()
18
19    def read_identity(self, cf):
20        cid = None
21        issuer = False
22        ct = abac_pem_type(cf)
23        if ct is None or ct =='cert':
24            cid = Creddy.ID(cf)
25        elif ct == 'both':
26            tkf = None
27            tcf = None
28            try:
29                tkf, tcf = abac_split_cert(cf)
30                cid = Creddy.ID(tcf)
31                cid.load_privkey(tkf)
32                issuer = True
33            finally:
34                if tkf: os.remove(tkf)
35                if tcf: os.remove(tcf)
36        return (cid, issuer)
37
38    def remember_credentials(self):
39        self.roles = set()
40        for c in self.ctxt.credentials():
41            h = c.head()
42            t = c.tail()
43
44            if h.is_role():
45                self.roles.add(h.role_name())
46
47            if t.is_role():
48                self.roles.add(t.role_name())
49            elif t.is_linking():
50                self.roles.add(re.sub('.*\.', '', t.linked_role()))
51                self.roles.add(t.role_name())
52
53    def clear(self):
54        self.ctxt = ABAC.Context()
55        self.names = { }
56        self.keyids = { }
57        self.issuers = { }
58        self.actions = set()
59        self.roles = set()
60        self.filename = None
61
62    def read_directory(self, dirname, clearit=True):
63        if clearit: self.clear()
64        attrs = [ ]
65        for p, dirs, files in os.walk(dirname):
66            for f in files:
67                if f == 'actions.txt':
68                    try:
69                        af = open(os.path.join(p, f))
70                        for l in af:
71                            self.actions.add(l.strip())
72                        af.close()
73                    except EnvironmentError, e:
74                        print >>sys.stderr, 'Cannot read %s: %s' % (
75                                e.filename, e.strerror)
76                elif not f.endswith('.pem') and not f.endswith('.der'):
77                    continue
78                cf = os.path.join(p, f)
79                try:
80                    cid, issuer = self.read_identity(cf)
81                except RuntimeError, e:
82                    attrs.append(cf)
83                    cid = None
84
85                if cid: 
86                    n = re.sub('_ID.pem', '', cid.cert_filename())
87                    self.names[cid.keyid()] = n
88                    self.keyids[n] = cid.keyid()
89                    if issuer: self.issuers[cid.keyid()] = cid
90                    err = self.ctxt.load_id_chunk(cid.cert_chunk())
91                    if err != ABAC.ABAC_CERT_SUCCESS:
92                        print >>sys.stderr, \
93                                "Cannot load chunk from %s: %d" % (cf, err)
94            for cf in attrs:
95                if self.ctxt.load_attribute_file(cf) != ABAC.ABAC_CERT_SUCCESS:
96                    print >>sys.stderr, "Cannot load %s" % cf
97
98        self.remember_credentials()
99
100    def read_zip(self, zipname, clearit=True):
101        d = tempfile.mkdtemp()
102        zf = zipfile.ZipFile(zipname)
103        zf.extractall(d)
104        self.read_directory(d, clearit)
105        remove_dirs(d)
106        self.filename = zipname
107
108    def write_zip(self, zipname):
109        old = os.getcwd()
110        d = tempfile.mkdtemp()
111        z = zipfile.ZipFile(zipname, 'w', compression=zipfile.ZIP_DEFLATED)
112        os.chdir(d)
113        os.mkdir('creds')
114        seenit = set()
115        issuer_no = 0
116        attr_no = 0
117        for cid in self.issuers.values():
118            if cid not in seenit:
119                try:
120                    f = open(os.path.join('creds', 
121                        'issuer%03d.pem' % issuer_no), 'w')
122                    issuer_no += 1
123                    cid.write_cert(f)
124                    cid.write_privkey(f)
125                    f.close()
126                    seenit.add(cid.cert_chunk())
127                except RuntimeError, e:
128                    print >>sys.stderr, 'Error writing issuer %s' % e
129        for cred in self.ctxt.credentials():
130            issuer_cert = cred.issuer_cert()
131            if issuer_cert not in seenit:
132                try:
133                    f = open(os.path.join('creds', 
134                        'issuer%03d.der' % issuer_no), 'w')
135                    issuer_no += 1
136                    f.write(issuer_cert)
137                    f.close()
138                    seenit.add(issuer_cert)
139                except:
140                    print >>sys.stderr, 'Error writing issuer'
141            attr_cert = cred.attribute_cert()
142            if attr_cert not in seenit:
143                try:
144                    f = open(os.path.join('creds', 
145                        'attr%03d.der' % attr_no), 'w')
146                    attr_no += 1
147                    f.write(attr_cert)
148                    f.close()
149                    seenit.add(attr_cert)
150                except:
151                    print >>sys.stderr, 'Error writing attribute'
152        try:
153            f = open(os.path.join('creds', 'actions.txt'), 'w')
154            for a in self.actions:
155                print >>f, a
156            f.close()
157        except EnvironmentError, e:
158            print >>sys.stderr, 'Error writing actions to %s: %s' % \
159                    (e.filename, e.strerror)
160        for p, dirs, files in os.walk('.'):
161            for f in files:
162                z.write(os.path.join(p, f))
163        z.close()
164        self.filename = zipname
165        os.chdir(old)
166        remove_dirs(d)
167
168    def translate_cred_roles(self, cred):
169        h = cred.head()
170        t = cred.tail()
171        issuer = h.principal()
172        role = h.role_name()
173
174        if t.is_principal():
175            return self.replace_keyids("%s says %s acts in role %s" % \
176                    ( issuer, t.principal(), role))
177        elif t.is_role():
178            return self.replace_keyids(("%s says any principal that %s " + \
179                    "says acts in role %s acts in role %s") % \
180                    (issuer, t.principal(), t.role_name(), role))
181        else:
182            lr = re.sub('.*\.', '', t.linked_role())
183            return self.replace_keyids(("%s says any principal that a " + \
184                    "principal that %s says acts in the role of %s " + \
185                    "says acts in role %s acts in role %s") % \
186                    (issuer, t.principal(), lr, t.role_name(), role))
187
188    def translate_cred_sets(self, cred):
189        h = cred.head()
190        t = cred.tail()
191        issuer = h.principal()
192        role = h.role_name()
193
194        if t.is_principal():
195            return self.replace_keyids("%s says %s is in its %s set" % \
196                    ( issuer, t.principal(), role))
197        elif t.is_role():
198            return self.replace_keyids(("%s says any principal in %s's " + \
199                    "%s set is in %s's %s set") % \
200                    (issuer, t.principal(), t.role_name(), issuer, role))
201        else:
202            lr = re.sub('.*\.', '', t.linked_role())
203            return self.replace_keyids(("%s says any principal in %s's " + \
204                    "%s set can put a principal in %s's %s set by putting " + \
205                    " that principal in %s") % \
206                    (issuer, t.principal(), lr, issuer, role, t.role_name()))
207
208    def translate_cred_keyids(self, cred):
209        return self.replace_keyids("%s<-%s" % \
210                (cred.head().string(), cred.tail().string()))
211
212    def translate_cred_null(self, cred):
213        return "%s<-%s" % (cred.head().string(), cred.tail().string())
214
215    def translate_cred(self, cred):
216        if self.translate == 'sets': return self.translate_cred_sets(cred)
217        elif self.translate == 'roles': return self.translate_cred_roles(cred)
218        elif self.translate == 'keyids': return self.translate_cred_keyids(cred)
219        elif self.translate == 'none': return self.translate_cred_null(cred)
220        else: return 'Bad type of translation (%s)???' % self.translate
221
222    @staticmethod
223    def is_issuer(cid):
224        tf = tempfile.TemporaryFile()
225        try:
226            cid.write_privkey(tf)
227            return True
228        except:
229            return False
230
231    def add_credential(self, cert):
232        '''
233        Cert is a Creddy.Credential
234        '''
235        rv = self.ctxt.load_attribute_chunk(cert.cert_chunk())
236        self.remember_credentials()
237        return rv
238
239    def remove_credentials(self, creds):
240        if isinstance(creds, list):
241            cs = set(["%s<-%s" % (c.head().string, c.tail.string()) \
242                    for c in creds])
243        else:
244            cs = set(["%s<-%s" % (creds.head().string, creds.tail.string())])
245
246        nc = ABAC.Context()
247        for c in self.ctxt.credentials():
248            crid = "%s<-%s" % (c.head().string, c.tail.string())
249            if crid not in cs:
250                nc.load_id_chunk(c.issuer_cert())
251                nc.load_attribute_chunk(c.attribute_cert())
252        self.ctxt = nc
253
254    def add_identity(self, cid):
255        '''
256        cid is a Creddy.ID
257        '''
258        rv = self.ctxt.load_attribute_chunk(cid.cert_chunk())
259        if self.is_issuer(cid):
260            self.issuers[cid.keyid()] = cid
261        n = re.sub('_ID.pem', '', cid.cert_filename())
262        self.names[cid.keyid()] = n
263        self.keyids[n] = cid.keyid()
264
265    def add_action(self, a):
266        self.actions.add(a)
267
268    def credentials(self):
269        return self.ctxt.credentials()
270
271    def query(self, role, principal):
272        return self.ctxt.query(role, principal)
273
274    def principal_keyids(self):
275        return self.names.keys()
276
277    def principal_names(self):
278        return self.names.values()
279
280    def principal_items(self):
281        return self.names.items()
282
283    def replace_keyids(self, s):
284        for k,r in self.names.items():
285            s = re.sub(k, r, s)
286        return s
287
288    def name_to_keyid(self, n):
289        return self.keyids.get(n, n)
Note: See TracBrowser for help on using the repository browser.