merge master again (2.0-10 changelog only)
[sfa.git] / sfa / trust / rights.py
index 2e2660f..eb0bb74 100644 (file)
@@ -1,44 +1,53 @@
 ##
-# This Module implements rights and lists of rights for the Geni wrapper. Rights
+# This Module implements rights and lists of rights for the SFA. Rights
 # are implemented by two classes:
 #
 # Right - represents a single right
 #
-# RightList - represents a list of rights
+# Rights - represents a list of rights
 #
 # A right may allow several different operations. For example, the "info" right
 # allows "listslices", "listcomponentresources", etc.
 ##
 
+
+
 ##
 # privilege_table is a list of priviliges and what operations are allowed
 # per privilege.
+# Note that "*" is a privilege granted by ProtoGENI slice authorities, and we
+# give it access to the GENI AM calls
 
-privilege_table = {"authority": ["register", "remove", "update", "resolve", "list", "getcredential"],
+privilege_table = {"authority": ["register", "remove", "update", "resolve", "list", "getcredential", "*"],
                    "refresh": ["remove", "update"],
                    "resolve": ["resolve", "list", "getcredential"],
-                   "sa": ["getticket", "redeemslice", "createslice", "deleteslice", "updateslice", 
-                          "getsliceresources", "getticket", "loanresources", "stopslice", "startslice", 
-                          "deleteslice", "resetslice", "listslices", "listnodes", "getpolicy"],
-                   "embed": ["getticket", "redeemslice", "createslice", "deleteslice", "updateslice", "getsliceresources"],
-                   "bind": ["getticket", "loanresources"],
-                   "control": ["updateslice", "createslice", "stopslice", "startslice", "deleteslice", "resetslice", "getsliceresources"],
+                   "sa": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "deleteslice", "deletesliver", "updateslice",
+                          "getsliceresources", "getticket", "loanresources", "stopslice", "startslice", "renewsliver",
+                          "deleteslice", "deletesliver", "resetslice", "listslices", "listnodes", "getpolicy", "sliverstatus"],
+                   "embed": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "renewsliver", "deleteslice", 
+                             "deletesliver", "updateslice", "sliverstatus", "getsliceresources", "shutdown"],
+                   "bind": ["getticket", "loanresources", "redeemticket"],
+                   "control": ["updateslice", "createslice", "createsliver", "renewsliver", "sliverstatus", "stopslice", "startslice", 
+                               "deleteslice", "deletesliver", "resetslice", "getsliceresources", "getgids"],
                    "info": ["listslices", "listnodes", "getpolicy"],
-                   "ma": ["setbootstate", "getbootstate", "reboot"]}
+                   "ma": ["setbootstate", "getbootstate", "reboot", "getgids", "gettrustedcerts"],
+                   "operator": ["gettrustedcerts", "getgids"],                   
+                   "*": ["createsliver", "deletesliver", "sliverstatus", "renewsliver", "shutdown"]} 
+
 
 
 ##
-# Determine tje rights that an object should have. The rights are entirely
+# Determine the rights that an object should have. The rights are entirely
 # dependent on the type of the object. For example, users automatically
 # get "refresh", "resolve", and "info".
 #
 # @param type the type of the object (user | sa | ma | slice | node)
 # @param name human readable name of the object (not used at this time)
 #
-# @return RightList object containing rights
+# @return Rights object containing rights
 
 def determine_rights(type, name):
-    rl = RightList()
+    rl = Rights()
 
     # rights seem to be somewhat redundant with the type of the credential.
     # For example, a "sa" credential implies the authority right, because
@@ -48,18 +57,23 @@ def determine_rights(type, name):
         rl.add("refresh")
         rl.add("resolve")
         rl.add("info")
-    elif type == "sa":
-        rl.add("authority,sa")
-    elif type == "ma":
-        rl.add("authority,ma")
+    elif type in ["sa", "authority+sa"]:
+        rl.add("authority")
+        rl.add("sa")
+    elif type in ["ma", "authority+ma", "cm", "authority+cm", "sm", "authority+sm"]:
+        rl.add("authority")
+        rl.add("ma")
     elif type == "authority":
-        rl.add("authority,sa,ma")
+        rl.add("authority")
+        rl.add("sa")
+        rl.add("ma")
     elif type == "slice":
         rl.add("refresh")
         rl.add("embed")
         rl.add("bind")
         rl.add("control")
         rl.add("info")
+# wouldn't that be authority+cm instead ?
     elif type == "component":
         rl.add("operator")
     return rl
@@ -71,55 +85,59 @@ def determine_rights(type, name):
 
 
 class Right:
-   ##
-   # Create a new right.
-   #
-   # @param kind is a string naming the right. For example "control"
+    ##
+    # Create a new right.
+    #
+    # @param kind is a string naming the right. For example "control"
+
+    def __init__(self, kind, delegate=False):
+        self.kind = kind
+        self.delegate = delegate
 
-   def __init__(self, kind):
-      self.kind = kind
+    ##
+    # Test to see if this right object is allowed to perform an operation.
+    # Returns True if the operation is allowed, False otherwise.
+    #
+    # @param op_name is a string naming the operation. For example "listslices".
 
-   ##
-   # Test to see if this right object is allowed to perform an operation.
-   # Returns True if the operation is allowed, False otherwise.
-   #
-   # @param op_name is a string naming the operation. For example "listslices".
+    def can_perform(self, op_name):
+        allowed_ops = privilege_table.get(self.kind.lower(), None)
+        if not allowed_ops:
+            return False
 
-   def can_perform(self, op_name):
-      allowed_ops = privilege_table.get(self.kind.lower(), None)
-      if not allowed_ops:
-         return False
+        # if "*" is specified, then all ops are permitted
+        if "*" in allowed_ops:
+            return True
 
-      # if "*" is specified, then all ops are permitted
-      if "*" in allowed_ops:
-         return True
+        return (op_name.lower() in allowed_ops)
 
-      return (op_name.lower() in allowed_ops)
+    ##
+    # Test to see if this right is a superset of a child right. A right is a
+    # superset if every operating that is allowed by the child is also allowed
+    # by this object.
+    #
+    # @param child is a Right object describing the child right
 
-   ##
-   # Test to see if this right is a superset of a child right. A right is a
-   # superset if every operating that is allowed by the child is also allowed
-   # by this object.
-   #
-   # @param child is a Right object describing the child right
+    def is_superset(self, child):
+        my_allowed_ops = privilege_table.get(self.kind.lower(), None)
+        child_allowed_ops = privilege_table.get(child.kind.lower(), None)
 
-   def is_superset(self, child):
-      my_allowed_ops = privilege_table.get(self.kind.lower(), None)
-      child_allowed_ops = privilege_table.get(child.kind.lower(), None)
+        if not self.delegate:
+            return False
 
-      if "*" in my_allowed_ops:
-          return True
+        if "*" in my_allowed_ops:
+            return True
 
-      for right in child_allowed_ops:
-          if not right in my_allowed_ops:
-              return False
+        for right in child_allowed_ops:
+            if not right in my_allowed_ops:
+                return False
 
-      return True
+        return True
 
 ##
-# A RightList object represents a list of privileges.
+# A Rights object represents a list of privileges.
 
-class RightList:
+class Rights:
     ##
     # Create a new rightlist object, containing no rights.
     #
@@ -138,9 +156,9 @@ class RightList:
     #
     # @param right is either a Right object or a string describing the right
 
-    def add(self, right):
+    def add(self, right, delegate=False):
         if isinstance(right, str):
-            right = Right(kind = right)
+            right = Right(right, delegate)
         self.rights.append(right)
 
     ##
@@ -155,7 +173,14 @@ class RightList:
 
         parts = string.split(",")
         for part in parts:
-            self.rights.append(Right(part))
+            if ':' in part:
+                spl = part.split(':')
+                kind = spl[0].strip()
+                delegate = bool(int(spl[1]))
+            else:
+                kind = part.strip()
+                delegate = 0
+            self.rights.append(Right(kind, bool(delegate)))
 
     ##
     # Save the rightlist object to a string. It is saved in the format of a
@@ -164,7 +189,7 @@ class RightList:
     def save_to_string(self):
         right_names = []
         for right in self.rights:
-            right_names.append(right.kind)
+            right_names.append('%s:%d' % (right.kind.strip(), right.delegate))
 
         return ",".join(right_names)
 
@@ -176,6 +201,7 @@ class RightList:
     # @param op_name is an operation to check, for example "listslices"
 
     def can_perform(self, op_name):
+        
         for right in self.rights:
             if right.can_perform(op_name):
                 return True
@@ -195,46 +221,29 @@ class RightList:
             for my_right in self.rights:
                 if my_right.is_superset(child_right):
                     allowed = True
+                    break
             if not allowed:
                 return False
         return True
 
 
     ##
-    # Determine tje rights that an object should have. The rights are entirely
-    # dependent on the type of the object. For example, users automatically
-    # get "refresh", "resolve", and "info".
-    #
-    # @param type the type of the object (user | sa | ma | slice | node)
-    # @param name human readable name of the object (not used at this time)
+    # set the delegate bit to 'delegate' on
+    # all privileges
     #
-    # @return RightList object containing rights
-
-    def determine_rights(self, type, name):
-        rl = RightList()
-
-        # rights seem to be somewhat redundant with the type of the credential.
-        # For example, a "sa" credential implies the authority right, because
-        # a sa credential cannot be issued to a user who is not an owner of
-        # the authority
-
-        if type == "user":
-            rl.add("refresh")
-            rl.add("resolve")
-            rl.add("info")
-        elif type == "sa":
-            rl.add("authority,sa")
-        elif type == "ma":
-            rl.add("authority,ma")
-        elif type == "authority":
-            rl.add("authority,sa,ma")
-        elif type == "slice":
-            rl.add("refresh")
-            rl.add("embed")
-            rl.add("bind")
-            rl.add("control")
-            rl.add("info")
-        elif type == "component":
-            rl.add("operator")
-
-        return rl
+    # @param delegate boolean (True or False)
+
+    def delegate_all_privileges(self, delegate):
+        for right in self.rights:
+            right.delegate = delegate
+
+    ##
+    # true if all privileges have delegate bit set true
+    # false otherwise
+
+    def get_all_delegate(self):
+        for right in self.rights:
+            if not right.delegate:
+                return False
+        return True
+