cosmetic: Right(s) have a __repr__
[sfa.git] / sfa / trust / rights.py
1 ##
2 # This Module implements rights and lists of rights for the SFA. Rights
3 # are implemented by two classes:
4 #
5 # Right - represents a single right
6 #
7 # Rights - represents a list of rights
8 #
9 # A right may allow several different operations. For example, the "info" right
10 # allows "listslices", "listcomponentresources", etc.
11 ##
12
13
14
15 ##
16 # privilege_table is a list of priviliges and what operations are allowed
17 # per privilege.
18 # Note that "*" is a privilege granted by ProtoGENI slice authorities, and we
19 # give it access to the GENI AM calls
20
21 privilege_table = {"authority": ["register", "remove", "update", "resolve", "list", "getcredential", "*"],
22                    "refresh": ["remove", "update"],
23                    "resolve": ["resolve", "list", "getcredential"],
24                    "sa": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "deleteslice", "deletesliver", "updateslice",
25                           "getsliceresources", "getticket", "loanresources", "stopslice", "startslice", "renewsliver",
26                           "deleteslice", "deletesliver", "resetslice", "listslices", "listnodes", "getpolicy", "sliverstatus"],
27                    "embed": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "renewsliver", "deleteslice", 
28                              "deletesliver", "updateslice", "sliverstatus", "getsliceresources", "shutdown"],
29                    "bind": ["getticket", "loanresources", "redeemticket"],
30                    "control": ["updateslice", "createslice", "createsliver", "renewsliver", "sliverstatus", "stopslice", "startslice", 
31                                "deleteslice", "deletesliver", "resetslice", "getsliceresources", "getgids"],
32                    "info": ["listslices", "listnodes", "getpolicy"],
33                    "ma": ["setbootstate", "getbootstate", "reboot", "getgids", "gettrustedcerts"],
34                    "operator": ["gettrustedcerts", "getgids"],                   
35                    "*": ["createsliver", "deletesliver", "sliverstatus", "renewsliver", "shutdown"]} 
36
37
38
39 ##
40 # Determine the rights that an object should have. The rights are entirely
41 # dependent on the type of the object. For example, users automatically
42 # get "refresh", "resolve", and "info".
43 #
44 # @param type the type of the object (user | sa | ma | slice | node)
45 # @param name human readable name of the object (not used at this time)
46 #
47 # @return Rights object containing rights
48
49 def determine_rights(type, name):
50     rl = Rights()
51
52     # rights seem to be somewhat redundant with the type of the credential.
53     # For example, a "sa" credential implies the authority right, because
54     # a sa credential cannot be issued to a user who is not an owner of
55     # the authority
56     if type == "user":
57         rl.add("refresh")
58         rl.add("resolve")
59         rl.add("info")
60     elif type in ["sa", "authority+sa"]:
61         rl.add("authority")
62         rl.add("sa")
63     elif type in ["ma", "authority+ma", "cm", "authority+cm", "sm", "authority+sm"]:
64         rl.add("authority")
65         rl.add("ma")
66     elif type == "authority":
67         rl.add("authority")
68         rl.add("sa")
69         rl.add("ma")
70     elif type == "slice":
71         rl.add("refresh")
72         rl.add("embed")
73         rl.add("bind")
74         rl.add("control")
75         rl.add("info")
76 # wouldn't that be authority+cm instead ?
77     elif type == "component":
78         rl.add("operator")
79     return rl
80
81
82 ##
83 # The Right class represents a single privilege.
84
85
86
87 class Right:
88     ##
89     # Create a new right.
90     #
91     # @param kind is a string naming the right. For example "control"
92
93     def __init__(self, kind, delegate=False):
94         self.kind = kind
95         self.delegate = delegate
96
97     def __repr__ (self): return "<Rgt:%s>"%self.kind
98
99     ##
100     # Test to see if this right object is allowed to perform an operation.
101     # Returns True if the operation is allowed, False otherwise.
102     #
103     # @param op_name is a string naming the operation. For example "listslices".
104
105     def can_perform(self, op_name):
106         allowed_ops = privilege_table.get(self.kind.lower(), None)
107         if not allowed_ops:
108             return False
109
110         # if "*" is specified, then all ops are permitted
111         if "*" in allowed_ops:
112             return True
113
114         return (op_name.lower() in allowed_ops)
115
116     ##
117     # Test to see if this right is a superset of a child right. A right is a
118     # superset if every operating that is allowed by the child is also allowed
119     # by this object.
120     #
121     # @param child is a Right object describing the child right
122
123     def is_superset(self, child):
124         my_allowed_ops = privilege_table.get(self.kind.lower(), None)
125         child_allowed_ops = privilege_table.get(child.kind.lower(), None)
126
127         if not self.delegate:
128             return False
129
130         if "*" in my_allowed_ops:
131             return True
132
133         for right in child_allowed_ops:
134             if not right in my_allowed_ops:
135                 return False
136
137         return True
138
139 ##
140 # A Rights object represents a list of privileges.
141
142 class Rights:
143     ##
144     # Create a new rightlist object, containing no rights.
145     #
146     # @param string if string!=None, load the rightlist from the string
147
148     def __init__(self, string=None):
149         self.rights = []
150         if string:
151             self.load_from_string(string)
152
153     def __repr__ (self): return "[" + " ".join( ["%s"%r for r in self.rights]) + "]"
154
155     def is_empty(self):
156         return self.rights == []
157
158     ##
159     # Add a right to this list
160     #
161     # @param right is either a Right object or a string describing the right
162
163     def add(self, right, delegate=False):
164         if isinstance(right, str):
165             right = Right(right, delegate)
166         self.rights.append(right)
167
168     ##
169     # Load the rightlist object from a string
170
171     def load_from_string(self, string):
172         self.rights = []
173
174         # none == no rights, so leave the list empty
175         if not string:
176             return
177
178         parts = string.split(",")
179         for part in parts:
180             if ':' in part:
181                 spl = part.split(':')
182                 kind = spl[0].strip()
183                 delegate = bool(int(spl[1]))
184             else:
185                 kind = part.strip()
186                 delegate = 0
187             self.rights.append(Right(kind, bool(delegate)))
188
189     ##
190     # Save the rightlist object to a string. It is saved in the format of a
191     # comma-separated list.
192
193     def save_to_string(self):
194         right_names = []
195         for right in self.rights:
196             right_names.append('%s:%d' % (right.kind.strip(), right.delegate))
197
198         return ",".join(right_names)
199
200     ##
201     # Check to see if some right in this list allows an operation. This is
202     # done by evaluating the can_perform function of each operation in the
203     # list.
204     #
205     # @param op_name is an operation to check, for example "listslices"
206
207     def can_perform(self, op_name):
208         
209         for right in self.rights:
210             if right.can_perform(op_name):
211                 return True
212         return False
213
214     ##
215     # Check to see if all of the rights in this rightlist are a superset
216     # of all the rights in a child rightlist. A rightlist is a superset
217     # if there is no operation in the child rightlist that cannot be
218     # performed in the parent rightlist.
219     #
220     # @param child is a rightlist object describing the child
221
222     def is_superset(self, child):
223         for child_right in child.rights:
224             allowed = False
225             for my_right in self.rights:
226                 if my_right.is_superset(child_right):
227                     allowed = True
228                     break
229             if not allowed:
230                 return False
231         return True
232
233
234     ##
235     # set the delegate bit to 'delegate' on
236     # all privileges
237     #
238     # @param delegate boolean (True or False)
239
240     def delegate_all_privileges(self, delegate):
241         for right in self.rights:
242             right.delegate = delegate
243
244     ##
245     # true if all privileges have delegate bit set true
246     # false otherwise
247
248     def get_all_delegate(self):
249         for right in self.rights:
250             if not right.delegate:
251                 return False
252         return True
253