From: Mark Huang <mlhuang@cs.princeton.edu>
Date: Fri, 15 Dec 2006 18:39:51 +0000 (+0000)
Subject: - make Peer a wrapper around xmlrpclib.ServerProxy, that also magically
X-Git-Tag: pycurl-7_13_1~194
X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=92684276bee3975ff99cf392b7691fa9734b0309;p=plcapi.git

- make Peer a wrapper around xmlrpclib.ServerProxy, that also magically
  signs each call and checks the SSL certificate
---

diff --git a/PLC/Peers.py b/PLC/Peers.py
index a80d87f6..ba9029d2 100644
--- a/PLC/Peers.py
+++ b/PLC/Peers.py
@@ -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