1 #----------------------------------------------------------------------
2 # Copyright (c) 2008 Board of Trustees, Princeton University
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and/or hardware specification (the "Work") to
6 # deal in the Work without restriction, including without limitation the
7 # rights to use, copy, modify, merge, publish, distribute, sublicense,
8 # and/or sell copies of the Work, and to permit persons to whom the Work
9 # is furnished to do so, subject to the following conditions:
11 # The above copyright notice and this permission notice shall be
12 # included in all copies or substantial portions of the Work.
14 # THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
22 #----------------------------------------------------------------------
24 # This Module implements rights and lists of rights for the SFA. Rights
25 # are implemented by two classes:
27 # Right - represents a single right
29 # Rights - represents a list of rights
31 # A right may allow several different operations. For example, the "info" right
32 # allows "listslices", "listcomponentresources", etc.
37 # privilege_table is a list of priviliges and what operations are allowed
39 # Note that "*" is a privilege granted by ProtoGENI slice authorities, and we
40 # give it access to the GENI AM calls
42 privilege_table = {"authority": ["register", "remove", "update", "resolve", "list", "getcredential", "*"],
43 "refresh": ["remove", "update"],
44 "resolve": ["resolve", "list", "getcredential"],
45 "sa": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "deleteslice", "deletesliver", "updateslice",
46 "getsliceresources", "getticket", "loanresources", "stopslice", "startslice", "renewsliver",
47 "deleteslice", "deletesliver", "resetslice", "listslices", "listnodes", "getpolicy", "sliverstatus"],
48 "embed": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "renewsliver", "deleteslice",
49 "deletesliver", "updateslice", "sliverstatus", "getsliceresources", "shutdown"],
50 "bind": ["getticket", "loanresources", "redeemticket"],
51 "control": ["updateslice", "createslice", "createsliver", "renewsliver", "sliverstatus", "stopslice", "startslice",
52 "deleteslice", "deletesliver", "resetslice", "getsliceresources", "getgids"],
53 "info": ["listslices", "listnodes", "getpolicy"],
54 "ma": ["setbootstate", "getbootstate", "reboot", "getgids", "gettrustedcerts"],
55 "operator": ["gettrustedcerts", "getgids"],
56 "*": ["createsliver", "deletesliver", "sliverstatus", "renewsliver", "shutdown"]}
60 # Determine the rights that an object should have. The rights are entirely
61 # dependent on the type of the object. For example, users automatically
62 # get "refresh", "resolve", and "info".
64 # @param type the type of the object (user | sa | ma | slice | node)
65 # @param name human readable name of the object (not used at this time)
67 # @return Rights object containing rights
69 def determine_rights(type, name):
72 # rights seem to be somewhat redundant with the type of the credential.
73 # For example, a "sa" credential implies the authority right, because
74 # a sa credential cannot be issued to a user who is not an owner of
80 elif type in ["sa", "authority+sa"]:
83 elif type in ["ma", "authority+ma", "cm", "authority+cm", "sm", "authority+sm"]:
86 elif type == "authority":
96 # wouldn't that be authority+cm instead ?
97 elif type == "component":
103 # The Right class represents a single privilege.
108 # Create a new right.
110 # @param kind is a string naming the right. For example "control"
112 def __init__(self, kind, delegate=False):
114 self.delegate = delegate
116 def __repr__(self): return "<Rgt:%s>" % self.kind
119 # Test to see if this right object is allowed to perform an operation.
120 # Returns True if the operation is allowed, False otherwise.
122 # @param op_name is a string naming the operation. For example "listslices".
124 def can_perform(self, op_name):
125 allowed_ops = privilege_table.get(self.kind.lower(), None)
129 # if "*" is specified, then all ops are permitted
130 if "*" in allowed_ops:
133 return (op_name.lower() in allowed_ops)
136 # Test to see if this right is a superset of a child right. A right is a
137 # superset if every operating that is allowed by the child is also allowed
140 # @param child is a Right object describing the child right
142 def is_superset(self, child):
143 my_allowed_ops = privilege_table.get(self.kind.lower(), None)
144 child_allowed_ops = privilege_table.get(child.kind.lower(), None)
146 if not self.delegate:
149 if "*" in my_allowed_ops:
152 for right in child_allowed_ops:
153 if not right in my_allowed_ops:
159 # A Rights object represents a list of privileges.
164 # Create a new rightlist object, containing no rights.
166 # @param string if string!=None, load the rightlist from the string
168 def __init__(self, string=None):
171 self.load_from_string(string)
173 def __repr__(self): return "[" + \
174 " ".join(["%s" % r for r in self.rights]) + "]"
177 return self.rights == []
180 # Add a right to this list
182 # @param right is either a Right object or a string describing the right
184 def add(self, right, delegate=False):
185 if isinstance(right, str):
186 right = Right(right, delegate)
187 self.rights.append(right)
190 # Load the rightlist object from a string
192 def load_from_string(self, string):
195 # none == no rights, so leave the list empty
199 parts = string.split(",")
202 spl = part.split(':')
203 kind = spl[0].strip()
204 delegate = bool(int(spl[1]))
208 self.rights.append(Right(kind, bool(delegate)))
211 # Save the rightlist object to a string. It is saved in the format of a
212 # comma-separated list.
214 def save_to_string(self):
216 for right in self.rights:
217 right_names.append('%s:%d' % (right.kind.strip(), right.delegate))
219 return ",".join(right_names)
222 # Check to see if some right in this list allows an operation. This is
223 # done by evaluating the can_perform function of each operation in the
226 # @param op_name is an operation to check, for example "listslices"
228 def can_perform(self, op_name):
230 for right in self.rights:
231 if right.can_perform(op_name):
236 # Check to see if all of the rights in this rightlist are a superset
237 # of all the rights in a child rightlist. A rightlist is a superset
238 # if there is no operation in the child rightlist that cannot be
239 # performed in the parent rightlist.
241 # @param child is a rightlist object describing the child
243 def is_superset(self, child):
244 for child_right in child.rights:
246 for my_right in self.rights:
247 if my_right.is_superset(child_right):
255 # set the delegate bit to 'delegate' on
258 # @param delegate boolean (True or False)
260 def delegate_all_privileges(self, delegate):
261 for right in self.rights:
262 right.delegate = delegate
265 # true if all privileges have delegate bit set true
268 def get_all_delegate(self):
269 for right in self.rights:
270 if not right.delegate:
274 def pretty_rights(self):
275 return "<Rights{}>".format(";".join(["{}".format(r) for r in self.rights]))