Fix big leak in type-checking add/update args for taggable classes
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sat, 18 Jul 2009 10:53:35 +0000 (10:53 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sat, 18 Jul 2009 10:53:35 +0000 (10:53 +0000)
Thanks Marc for the heads up

PLC/Methods/AddInterface.py
PLC/Methods/AddNode.py
PLC/Methods/AddSlice.py
PLC/Methods/UpdateInterface.py
PLC/Methods/UpdateNode.py
PLC/Methods/UpdateSlice.py
PLC/Table.py

index cd3911a..662d7fd 100644 (file)
@@ -19,23 +19,21 @@ class AddInterface(Method):
 
     Adds a new network for a node. Any values specified in
     interface_fields are used, otherwise defaults are
-    used. Acceptable values for method may be retrieved via
-    GetNetworkMethods. Acceptable values for type may be retrieved via
-    GetNetworkTypes.
+    used. 
 
-    If type is static, ip, gateway, network, broadcast, netmask, and
-    dns1 must all be specified in interface_fields. If type is dhcp,
-    these parameters, even if specified, are ignored.
+    If type is static, then ip, gateway, network, broadcast, netmask,
+    and dns1 must all be specified in interface_fields. If type is
+    dhcp, these parameters, even if specified, are ignored.
 
-    PIs and techs may only add networks to their own nodes. Admins may
-    add networks to any node.
+    PIs and techs may only add interfaces to their own nodes. Admins may
+    add interfaces to any node.
 
     Returns the new interface_id (> 0) if successful, faults otherwise.
     """
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags])
+    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags], exclude=True)
 
     accepts = [
         Auth(),
@@ -49,6 +47,8 @@ class AddInterface(Method):
     
     def call(self, auth, node_id_or_hostname, interface_fields):
 
+        interface_fields = Row.check_fields (interface_fields, self.accepted_fields)
+
         [native,tags,rejected]=Row.split_fields(interface_fields,[Interface.fields,Interface.tags])
         if rejected:
             raise PLCInvalidArgument, "Cannot add Interface with column(s) %r"%rejected
index e8d073a..b722585 100644 (file)
@@ -40,6 +40,8 @@ class AddNode(Method):
 
     def call(self, auth, site_id_or_login_base, node_fields):
 
+        node_fields = Row.check_fields (node_fields, self.accepted_fields)
+
         [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags])
 
         if rejected:
index 001e0f9..3e2a89c 100644 (file)
@@ -46,6 +46,8 @@ class AddSlice(Method):
 
     def call(self, auth, slice_fields):
 
+        slice_fields = Row.check_fields (slice_fields, self.accepted_fields)
+
         [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags])
 
         if rejected:
index dad6420..48f3822 100644 (file)
@@ -31,7 +31,7 @@ class UpdateInterface(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags])
+    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags],exclude=True)
 
     accepts = [
         Auth(),
@@ -43,6 +43,8 @@ class UpdateInterface(Method):
 
     def call(self, auth, interface_id, interface_fields):
 
+        interface_fields = Row.check_fields (interface_fields, self.accepted_fields)
+
         [native,tags,rejected] = Row.split_fields(interface_fields,[Interface.fields,Interface.tags])
 
         if rejected:
index d66dd9e..ecfa6cf 100644 (file)
@@ -40,6 +40,8 @@ class UpdateNode(Method):
 
     def call(self, auth, node_id_or_hostname, node_fields):
         
+        node_fields = Row.check_fields (node_fields, self.accepted_fields)
+
         # split provided fields 
         [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
 
index 29d3bfd..feeb4da 100644 (file)
@@ -48,6 +48,8 @@ class UpdateSlice(Method):
 
     def call(self, auth, slice_id_or_name, slice_fields):
 
+        slice_fields = Row.check_fields (slice_fields, self.accepted_fields)
+
         # split provided fields 
         [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags])
 
index f37f206..fdd755e 100644 (file)
@@ -239,6 +239,30 @@ class Row(dict):
             else: rejected.append(column)
         return (fields,tags,rejected)
 
+    # compute the accepts part of an update method from a list of column names, and a (list of) fields dict
+    # use exclude=True to exclude the column names instead
+    @staticmethod
+    def accepted_fields (update_columns, fields, exclude=False):
+        if not isinstance(fields,list): fields = [fields]
+        result={}
+        for fields_dict in fields:
+            for (k,v) in fields_dict.iteritems():
+                if (not exclude and k in update_columns) or (exclude and k not in update_columns):
+                    result[k]=v
+        return result
+
+    # filter out user-provided fields that are not part of the declared acceptance list
+    # this could maybe have been integrated in split_fields, but for simplicity we keep it aside
+    @staticmethod
+    def check_fields (user_dict, accepted_fields):
+# avoid the simple, but silent, version
+#        return dict ([ (k,v) for (k,v) in user_dict.items() if k in accepted_fields ])
+        result={}
+        for (k,v) in user_dict.items():
+            if k in accepted_fields: result[k]=v
+            else: raise PLCInvalidArgument ('Trying to set/change unaccepted key %s'%k)
+        return result
+
     # given a dict (typically passed to an Update method), we check and sort
     # them against a list of dicts, e.g. [Node.fields, Node.related_fields]
     # return is a list that contains n+1 dicts, last one has the rejected fields
@@ -259,17 +283,6 @@ class Row(dict):
         result.append(rejected)
         return result
 
-    # compute the accepts part of an update method from a list of column names, and a (list of) fields dict
-    @staticmethod
-    def accepted_fields (can_update_columns, fields):
-        result={}
-        if not isinstance(fields,list): fields = [fields]
-        for dict in fields:
-            for (k,v) in dict.iteritems():
-                if k in can_update_columns:
-                    result[k]=v
-        return result
-
     ### class initialization : create tag-dependent cross view if needed
     @classmethod
     def tagvalue_view_name (cls, tagname):