[3f6bc5f] | 1 | #/usr/local/bin/python |
---|
| 2 | |
---|
| 3 | from fedid import fedid |
---|
| 4 | |
---|
| 5 | class authorizer: |
---|
| 6 | """ |
---|
| 7 | This class keeps track of authorization attributes for the various modules |
---|
| 8 | running. When it gets smarter it will be the basis for a real |
---|
| 9 | attribute-based authentication system. |
---|
| 10 | """ |
---|
| 11 | # general error exception for badly formed names. |
---|
| 12 | class bad_name(RuntimeError): pass |
---|
| 13 | |
---|
| 14 | def __init__(self, def_attr="testbed"): |
---|
| 15 | self.attrs = { } |
---|
[05191a6] | 16 | self.globals=set() |
---|
[3f6bc5f] | 17 | |
---|
| 18 | @staticmethod |
---|
| 19 | def auth_name(name): |
---|
| 20 | """ |
---|
| 21 | Helper to convert a non-unicode local name to a unicode string. Mixed |
---|
| 22 | representations can needlessly confuse the authorizer. |
---|
| 23 | """ |
---|
| 24 | if isinstance(name, basestring): |
---|
| 25 | if not isinstance(name, unicode): return unicode(name) |
---|
| 26 | else: return name |
---|
| 27 | else: return name |
---|
| 28 | |
---|
| 29 | def valid_name(self, name): |
---|
| 30 | """ |
---|
| 31 | Ensure that the given name is valid. A valid name can either be a |
---|
| 32 | triple of strings and fedids representing one of our generalized Emulab |
---|
| 33 | names or a single fedid. Compound names can include wildcards (None) |
---|
| 34 | and must anchor to a fedid at their highest level (unless they're all |
---|
| 35 | None) |
---|
| 36 | |
---|
| 37 | This either returns True or throws an exception. More an assertion |
---|
| 38 | than a function. |
---|
| 39 | """ |
---|
| 40 | if isinstance(name, tuple) and len(name) == 3: |
---|
| 41 | for n in name: |
---|
| 42 | if n: |
---|
| 43 | if not (isinstance(n, basestring) or isinstance(n, fedid)): |
---|
[0df6015] | 44 | raise self.bad_name("names must be either a " +\ |
---|
| 45 | "triple or a fedid") |
---|
[3f6bc5f] | 46 | for n in name: |
---|
| 47 | if n: |
---|
| 48 | if isinstance(n, fedid): |
---|
| 49 | return True |
---|
| 50 | else: |
---|
| 51 | raise self.bad_name("Compound names must be " + \ |
---|
| 52 | "rooted in fedids: %s" % str(name)) |
---|
| 53 | |
---|
| 54 | return True |
---|
| 55 | elif isinstance(name, fedid): |
---|
| 56 | return True |
---|
| 57 | else: |
---|
[0df6015] | 58 | raise self.bad_name("Names must be a triple or a fedid (%s)" % name) |
---|
[3f6bc5f] | 59 | |
---|
| 60 | def set_attribute(self, name, attr): |
---|
| 61 | """ |
---|
| 62 | Attach attr to name. Multiple attrs can be attached. |
---|
| 63 | """ |
---|
| 64 | self.valid_name(name) |
---|
| 65 | if isinstance(name, tuple): |
---|
| 66 | aname = tuple([ self.auth_name(n) for n in name]) |
---|
| 67 | else: |
---|
| 68 | aname = self.auth_name(name) |
---|
| 69 | |
---|
| 70 | if not self.attrs.has_key(aname): |
---|
| 71 | self.attrs[aname] = set() |
---|
| 72 | self.attrs[aname].add(attr) |
---|
| 73 | |
---|
| 74 | def unset_attribute(self, name, attr): |
---|
| 75 | """ |
---|
| 76 | Remove an attribute from name |
---|
| 77 | """ |
---|
| 78 | self.valid_name(name) |
---|
| 79 | if isinstance(name, tuple): |
---|
| 80 | aname = tuple([ self.auth_name(n) for n in name]) |
---|
| 81 | else: |
---|
| 82 | aname = self.auth_name(name) |
---|
| 83 | |
---|
| 84 | attrs = self.attrs.get(aname, None) |
---|
| 85 | if attrs: attrs.discard(attr) |
---|
| 86 | |
---|
| 87 | def check_attribute(self, name, attr): |
---|
| 88 | """ |
---|
[05191a6] | 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. |
---|
[3f6bc5f] | 93 | """ |
---|
| 94 | def tup(tup, i, p): |
---|
| 95 | mask = 1 << i |
---|
| 96 | if p & mask : return authorizer.auth_name(tup[i]) |
---|
| 97 | else: return None |
---|
| 98 | |
---|
| 99 | self.valid_name(name) |
---|
[05191a6] | 100 | if attr in self.globals: |
---|
| 101 | return True |
---|
[3f6bc5f] | 102 | |
---|
| 103 | if isinstance(name, tuple): |
---|
| 104 | for p in range(0,8): |
---|
| 105 | lookup = ( tup(name, 0, p), tup(name,1, p), tup(name,2,p)) |
---|
| 106 | if self.attrs.has_key(lookup): |
---|
| 107 | if attr in self.attrs[lookup]: |
---|
| 108 | return True |
---|
| 109 | else: |
---|
| 110 | return attr in self.attrs.get(self.auth_name(name), set()) |
---|
| 111 | |
---|
[05191a6] | 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) |
---|
| 118 | |
---|
| 119 | def unset_global_attribute(self, attr): |
---|
| 120 | """ |
---|
| 121 | Remove a global attribute |
---|
| 122 | """ |
---|
| 123 | |
---|
| 124 | self.globals.discard(attr) |
---|
[3f6bc5f] | 125 | |
---|