source: fedd/access_to_abac.py @ 9cce15a

axis_examplecompt_changesinfo-ops
Last change on this file since 9cce15a was 9cce15a, checked in by Ted Faber <faber@…>, 14 years ago

small changes

  • Property mode set to 100755
File size: 5.0 KB
Line 
1#!/usr/local/bin/python
2
3import sys, os
4import re
5
6from federation.fedid import fedid
7from optparse import OptionParser, OptionValueError
8
9class attribute:
10    def __init__(self, p, a):
11        self.principal = p
12        self.attr = a
13
14    def __str__(self):
15        return "%s.%s" % (self.principal, self.attr)
16
17class credential:
18    def __init__(self, p, a, req):
19        self.principal = p
20        if isinstance(a, (tuple, list, set)) and len(a) == 1:
21            self.attr = a[0]
22        else:
23            self.attr = a
24        self.req = req
25
26    def __str__(self):
27        if isinstance(self.req, (tuple, list, set)):
28            return "%s.%s <- %s" % (self.principal, self.attr, 
29                    " & ".join(["%s" % r for r in self.req]))
30        else:
31            return "%s.%s <- %s" % (self.principal, self.attr, self.req)
32
33class parse_error(RuntimeError): pass
34
35def parse_emulab(l, creds, me, to_id, p, gp, gu):
36    right_side_str = '\s*,\s*\(\s*%s\s*,\s*%s\s*,\s*%s\s*\)' % \
37            (id_same_str, id_same_str,id_same_str)
38
39    m = re.match(right_side_str, l)
40    if m:
41        project, user = m.group(1,2)
42        if project == '<same>':
43            if gp  is not None:
44                project = gp
45            else:
46                raise parse_error("Project cannot be decisively mapped: %s" % l)
47        if user == '<same>':
48            if gu is not None:
49                project = gu
50            else:
51                raise parse_error("User cannot be decisively mapped: %s" % l)
52        if project and user:
53            a = 'project_%s_user_%s' % (project, user)
54        elif project:
55            a = 'project_%s' % project
56        elif user:
57            a = 'user_%s' % user
58        else:
59            raise parse_error("No mapping for %s/%s!?" % (gp, gu))
60
61        c = credential(me, a, 
62                [attribute(p, x) for x in (gp, gu) if x is not None])
63        creds.add(c)
64        if a in to_id: to_id[a].append(c)
65        else: to_id[a] = [ c ]
66    else:
67        raise parse_error("Badly formatted local mapping: %s" % l)
68
69
70def parse_dragon(l, creds, me, to_id, p, gp, gu):
71    right_side_str = '\s*,\s*\(\s*(%s)\s*\)' % \
72            (id_str)
73
74    m = re.match(right_side_str, l)
75    if m:
76        repo= m.group(1)
77        c = credential(me, 'repo_%s' % repo, 
78                [attribute(p, x) for x in (gp, gu) if x is not None])
79        creds.add(c)
80        if repo in to_id: to_id[repo].append(c)
81        else: to_id[repo] = [ c ]
82    else:
83        raise parse_error("Badly formatted local mapping: %s" % l)
84
85parse_skel = parse_dragon
86
87def parse_internal(l, creds, me, to_id, p, gp, gu): pass
88
89
90class access_opts(OptionParser):
91    mappers = { 
92            'emulab': parse_emulab, 
93            'dragon': parse_dragon,
94            'internal': parse_internal,
95            'skel': parse_skel,
96            }
97
98    @staticmethod
99    def parse_mapper(opt, s, val, parser, dest):
100        if val in access_opts.mappers:
101            setattr(parser.values, dest, access_opts.mappers[val])
102        else:
103            raise OptionValueError('%s must be one of %s' % \
104                    (s, ", ".join(access_opts.mappers.keys())))
105
106    def __init__(self):
107        OptionParser.__init__(self, usage='%prog [opts] file [...]')
108        self.add_option('--cert', dest='cert', default=None,
109                help='my fedid as an X.509 certificate')
110        self.add_option('--key', dest='key', default=None,
111                help='key for the certificate')
112        self.add_option('--type', action='callback', nargs=1, type='str',
113                callback=access_opts.parse_mapper, 
114                callback_kwargs = { 'dest': 'mapper'}, 
115                help='Type of access file to parse.  One of %s. ' %\
116                        ", ".join(access_opts.mappers.keys()) + \
117                        'Omit for generic parsing.')
118        self.set_defaults(mapper=None)
119
120
121
122comment_re = re.compile('^\s*#|^$')
123fedid_str = 'fedid:([0-9a-fA-F]{40})'
124id_str = '[a-zA-Z][\w_-]*'
125id_any_str = '(%s|<any>)' % id_str
126id_same_str = '(%s|<same>)' % id_str
127left_side_str = '\(\s*%s\s*,\s*%s\s*,\s*%s\s*\)' % \
128        (fedid_str, id_any_str, id_any_str)
129right_side_str = '(%s)(\s*,\s*\(.*\))?' % (id_str)
130line_re = re.compile('%s\s*->\s*%s' % (left_side_str, right_side_str))
131
132p = access_opts()
133opts, args = p.parse_args()
134
135if len(args) < 1:
136    sys.exit('No filenames given to parse')
137
138if opts.cert: 
139    try:
140        me = fedid(file=opts.cert) 
141    except EnvironmentError, e:
142        sys.exit('Bad --cert: %s (%s)' % (e.strerror, e.filename or '?!'))
143else: 
144    print >>sys.stderr, 'No --cert, using dummy fedid'
145    me = fedid(hexstr='0123456789012345678901234567890123456789')
146
147mapper = opts.mapper
148
149for fn in args:
150    creds = set()
151    to_id = { }
152    try:
153        f = open(fn, "r")
154        for i, l in enumerate(f):
155            try:
156                if comment_re.match(l):
157                    continue
158                else:
159                    m =  line_re.match(l)
160                    if m:
161                        p, da = m.group(1, 4)
162                        gp, gu = m.group(2, 3)
163                        if gp == '<any>': gp = None
164                        if gu == '<any>': gu = None
165
166                        creds.add(credential(me, da, 
167                                [attribute(p, x) for x in (gp, gu) \
168                                    if x is not None]))
169                        if m.group(5) and mapper:
170                            mapper(m.group(5), creds, me, to_id, p, gp, gu)
171                    else:
172                        raise parse_error('Syntax error')
173            except parse_error, e:
174                raise parse_error('Error on line %d of %s: %s' % \
175                        (i, fn, e.message))
176               
177        f.close()
178    except parse_error, e:
179        print >> sys.stderr, "%s" % e
180        continue
181
182    except EnvironmentError, e:
183        print >>sys.stderr, "File error %s: %s" % \
184                (e.filename or '!?', e.strerror) 
185        continue
186
187    for c in creds:
188        print "%s" % c
189
190    for k, c in to_id.items():
191        print "%s: %s" % ( k , ", ".join(set(["%s.%s" % (x.principal, x.attr) \
192                for x in c])))
Note: See TracBrowser for help on using the repository browser.