- make Peer a wrapper around xmlrpclib.ServerProxy, that also magically
authorMark Huang <mlhuang@cs.princeton.edu>
Fri, 15 Dec 2006 18:39:51 +0000 (18:39 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Fri, 15 Dec 2006 18:39:51 +0000 (18:39 +0000)
  signs each call and checks the SSL certificate

PLC/Peers.py

index a80d87f..ba9029d 100644 (file)
@@ -6,14 +6,19 @@ import re
 from types import StringTypes
 
 from PLC.Faults import *
-from PLC.Parameter import Parameter
+from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
+import PLC.Auth
 
 from PLC.Nodes import Nodes,Node
 from PLC.Slices import Slices,Slice
 
-class Peer (Row):
+import xmlrpclib
+from PLC.PyCurl import PyCurlTransport
+from PLC.GPG import gpg_sign
+
+class Peer(Row):
     """
     Stores the list of peering PLCs in the peers table. 
     See the Row class for more details
@@ -25,8 +30,8 @@ class Peer (Row):
        'peer_id' : Parameter (int, "Peer identifier"),
        'peername' : Parameter (str, "Peer name"),
        'peer_url' : Parameter (str, "Peer API url"),
-        ### xxx this trick is temporary, for peer authentication
-       'auth_person_id' : Parameter (int, "Person_id of the account storing credentials - temporary"),
+       'key': Parameter(str, "Peer GPG public key"),
+       'cacert': Parameter(str, "Peer SSL public certificate"),
         ### cross refs
         'site_ids' : Parameter ([int], "This peer's sites ids"),
         'person_ids' : Parameter ([int], "This peer's persons ids"),
@@ -43,12 +48,6 @@ class Peer (Row):
            raise invalid_url
        return url
 
-    ### for use by RefreshPeer, *not* a method of the API
-    def update_name (self,peername):
-        if self['peername'] != peername:
-            self['peername']=peername
-            self.sync()
-
     def delete (self, commit=True):
        """
        Delete peer
@@ -64,6 +63,59 @@ class Peer (Row):
        self['deleted'] = True
        self.sync(commit)
 
+    def connect(self, **kwds):
+        """
+        Connect to this peer via XML-RPC.
+        """
+
+        self.server = xmlrpclib.ServerProxy(self['peer_url'],
+                                            PyCurlTransport(self['peer_url'], self['cacert']),
+                                            allow_none = 1, **kwds)
+
+    def add_auth(self, function, methodname, **kwds):
+        """
+        Sign the specified XML-RPC call and add an auth struct as the
+        first argument of the call.
+        """
+
+        def wrapper(*args, **kwds):
+            signature = gpg_sign(methodname, args,
+                                 self.api.config.PLC_ROOT_GPG_KEY,
+                                 self.api.config.PLC_ROOT_GPG_KEY_PUB)
+
+            auth = {'AuthMethod': "gpg",
+                    'name': self.api.config.PLC_NAME,
+                    'signature': signature}
+
+            # Automagically add auth struct to every call
+            args = (auth,) + args
+
+            return function(*args)
+
+        return wrapper
+
+    def __getattr__(self, methodname):
+        """
+        Fetch a callable for the specified method.
+        """
+
+        function = getattr(self.server, methodname)
+
+        try:
+            # Figure out if the function is a PLCAPI function and
+            # requires an authentication structure as its first
+            # argument.
+            api_function = self.api.callable(methodname)
+            if api_function.accepts and \
+               (isinstance(api_function.accepts[0], PLC.Auth.Auth) or \
+                (isinstance(api_function.accepts[0], Mixed) and \
+                 filter(lambda param: isinstance(param, Auth), func.accepts[0]))):
+                function = self.add_auth(function, methodname)
+        except Exception, err:
+            pass
+
+        return function
+
 class Peers (Table):
     """ 
     Maps to the peers table in the database