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