Index: fedd/fedd_allocate_project.py
===================================================================
--- fedd/fedd_allocate_project.py	(revision 7da9da6d3e2f324bb49a9b9403f751554663dd86)
+++ fedd/fedd_allocate_project.py	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -21,7 +21,8 @@
 from fedd_util import *
 import parse_detail
+from service_error import *
 
 class fedd_allocate_project_local:
-    def __init__(self, dp=False, url=None):
+    def __init__(self, dp=False, url=None, certs=None):
 	"""
 	Initializer.  Parses a configuration if one is given.
@@ -58,5 +59,5 @@
 
 
-    def dynamic_project(self, req):
+    def dynamic_project(self, req, fedid=None):
 	"""
 	Create a dynamic project with ssh access
@@ -70,6 +71,10 @@
 		dir="/tmp")
 
-	print userfile
-	proj = req['project']
+	if req.has_key('AllocateProjectRequestBody') and \
+		req['AllocateProjectRequestBody'].has_key('project'):
+	    proj = req['AllocateProjectRequestBody']['project']
+	else:
+	    raise service_error(service_error.req, 
+		    "Badly formed allocation request")
 	# Take the first user and ssh key
 	name = proj.get('name', None) or self.random_string("proj",4)
@@ -91,5 +96,5 @@
 	    access = user.get('access', None)
 	    if access != None:
-		ssh = access.get('sshPubkey', None)
+		ssh = access[0].get('sshPubkey', None)
 		if ssh == None:
 		    raise fedd_proj.service_error(fedd_proj.service_error.req, 
@@ -177,2 +182,65 @@
 	}
 	return rv
+
+
+class fedd_allocate_project_remote:
+    def __init__(self, dp=False, url=None, certs=None):
+	"""
+	Initializer.  Parses a configuration if one is given.
+	"""
+
+	self.dynamic_projects = dp
+	self.url = url
+
+	if certs != None and isinstance(certs, type(tuple())):
+	    self.cert_file, self.trusted_certs, self.cert_pwd = certs
+	    # self.cert_file = certs[0]
+	    # self.trusted_certs = certs[1]
+	    # self.cert_pwd = certs[2]
+	else:
+	    self.cert_file = None
+	    self.trusted_certs = None
+	    self.cert_pwd = None
+
+    def dynamic_project(self, req, fedid=None):
+	"""
+	Send req on to a remote project instantiator.
+
+	Req is just the projectAllocType object.  This function re-wraps it.
+	It also rethrows any faults.
+	"""
+	# No retry loop here.  Proxy servers must correctly authenticate
+	# themselves without help
+	try:
+	    ctx = fedd_ssl_context(self.cert_file, self.trusted_certs,
+		    password=self.cert_pwd)
+	except SSL.SSLError:
+	    raise service_error(service_error.server_config, 
+		    "Server certificates misconfigured")
+
+	loc = feddServiceLocator();
+	port = loc.getfeddPortType(self.url,
+		transport=M2Crypto.httpslib.HTTPSConnection, 
+		transdict={ 'ssl_context' : ctx })
+
+	if req.has_key('AllocateProjectRequestBody'):
+	    req = req['AllocateProjectRequestBody']
+	else:
+	    raise service_error(service_error.req, "Bad formated request");
+
+	# Reconstruct the full request message
+	msg = AllocateProjectRequestMessage()
+	msg.set_element_AllocateProjectRequestBody(
+		pack_soap(msg, "AllocateProjectRequestBody", req))
+	try:
+	    resp = port.AllocateProject(msg)
+	except ZSI.ParseException, e:
+	    raise service_error(service_error.proxy,
+		    "Bad format message (XMLRPC??): %s" % str(e))
+	r = unpack_soap(resp)
+
+	if r.has_key('AllocateProjectResponseBody'):
+	    return r['AllocateProjectResponseBody']
+	else:
+	    raise service_error(service_error.proxy, "Bad proxy response")
+
Index: fedd/fedd_messages.wsdl
===================================================================
--- fedd/fedd_messages.wsdl	(revision 7da9da6d3e2f324bb49a9b9403f751554663dd86)
+++ fedd/fedd_messages.wsdl	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -24,5 +24,6 @@
 
   <message name="AllocateProjectResponseMessage">
-    <part name="AllocateProjectResponseBody" type="xsd1:projectType"/>
+    <part name="AllocateProjectResponseBody" 
+      type="xsd1:projectAllocResponseType"/>
   </message>
 
Index: fedd/fedd_proj.py
===================================================================
--- fedd/fedd_proj.py	(revision 7da9da6d3e2f324bb49a9b9403f751554663dd86)
+++ fedd/fedd_proj.py	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -33,6 +33,8 @@
     bool_attrs = ("dynamic_projects", "project_priority")
     emulab_attrs = ("boss", "ops", "domain", "fileserver", "eventserver")
-    id_attrs = ("testbed", "cert_file", "trusted_certs", "proxy",
-	    "proxy_trusted_certs", "cert_pwd")
+    id_attrs = ("testbed", "cert_file", "cert_pwd", "trusted_certs", "proxy",
+	    "proxy_cert_file", "proxy_cert_pwd", "proxy_trusted_certs",
+	    "dynamic_projects_url", "dynamic_projects_cert_file", 
+	    "dynamic_projects_cert_pwd", "dynamic_projects_trusted_certs")
 
     # Used by the SOAP caller
@@ -92,6 +94,39 @@
 	if config != None: 
 	    self.read_config(config)
-	self.allocate_project = \
-	    fedd_allocate_project_local(self.dynamic_projects)
+
+	# Certs are promoted from the generic to the specific, so without a
+	# specific proxy certificate, the main certificates are used for proxy
+	# interactions. If no dynamic project certificates, then proxy certs
+	# are used, and if none of those the main certs.
+
+	# init proxy certs
+	if self.proxy_cert_file == None:
+	    self.proxy_cert_file = self.cert_file
+	    self.proxy_cert_pwd = self.cert_pwd
+
+	if self.proxy_trusted_certs == None:
+	    self.proxy_trusted_certs = self.trusted_certs
+
+	# init dynamic project certs
+	if self.dynamic_projects_cert_file == None:
+	    self.dynamic_projects_cert_file = self.proxy_cert_file
+	    self.dynamic_projects_cert_pwd = self.proxy_cert_pwd
+
+	if self.dynamic_projects_trusted_certs == None:
+	    self.dynamic_projects_trusted_certs = self.proxy_trusted_certs
+
+	proj_certs = (self.dynamic_projects_cert_file, 
+		self.dynamic_projects_trusted_certs,
+		self.dynamic_projects_cert_pwd)
+
+	if self.dynamic_projects_url == None:
+	    self.allocate_project = \
+		fedd_allocate_project_local(self.dynamic_projects, 
+			self.dynamic_projects_url, proj_certs)
+	    fedd_proj.soap_methods['AllocateProject'] = 'soap_AllocateProject'
+	else:
+	    self.allocate_project = \
+		fedd_allocate_project_remote(self.dynamic_projects, 
+			self.dynamic_projects_url, proj_certs)
 
     def dump_state(self):
@@ -138,10 +173,10 @@
     def proxy_xmlrpc_request(self, dt, req):
 	"""Send an XMLRPC proxy request.  Called if the SOAP RPC fails"""
-	tc = self.proxy_trusted_certs or self.trusted_certs
 
 	# No retry loop here.  Proxy servers must correctly authenticate
 	# themselves without help
 	try:
-	    ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
+	    ctx = fedd_ssl_context(self.proxy_cert_file, 
+		    self.proxy_trusted_certs, password=self.proxy_cert_pwd)
 	except SSL.SSLError:
 	    raise service_error(service_error.server_config,
@@ -186,10 +221,9 @@
 	also rethrows any faults.
 	"""
-	tc = self.proxy_trusted_certs or self.trusted_certs
-
 	# No retry loop here.  Proxy servers must correctly authenticate
 	# themselves without help
 	try:
-	    ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
+	    ctx = fedd_ssl_context(self.proxy_cert_file, 
+		    self.proxy_trusted_certs, password=self.proxy_cert_pwd)
 	except SSL.SSLError:
 	    raise service_error(service_error.server_config, 
@@ -401,18 +435,18 @@
 		    # Compose the dynamic project request 
 		    # (only dynamic, dynamic currently allowed)
-		    preq = { 'project' : {\
+		    preq = { 'AllocateProjectRequestBody': \
+				{ 'project' : {\
 				    'user': [ \
-				    { 'access': { 'sshPubkey': s } } \
+				    { 'access': [ { 'sshPubkey': s } ] } \
 					for s in ssh ] \
+				    }\
 				}\
 			    }
 		    if restricted != None and len(restricted) > 0:
-			preq['resources'] =  [ {'node': { 'hardware' :  [ h ]\
-			    } } for h in restricted ]
+			preq['AllocateProjectRequestBody']['resources'] = \
+			    [ {'node': { 'hardware' :  [ h ] } } \
+				    for h in restricted ]
 				
-
-		    #self.dynamic_project(found, ssh)
 		    ap = self.allocate_project.dynamic_project(preq)
-		    # XXX: fill in response values into the real response
 		else: pass    # SSH key additions
 	    else:
@@ -449,4 +483,16 @@
 			    service_error.proxy,
 			    "Undefined fault from proxy??");
+
+
+    def soap_AllocateProject(self, ps, fid):
+	req = ps.Parse(AllocateProjectRequestMessage.typecode)
+
+	msg = self.allocate_project.dynamic_project(unpack_soap(req), fedid)
+
+	resp = AllocateProjectResponseMessage()
+	resp.set_element_AllocateProjectResponseBody(
+		pack_soap(resp, "AllocateProjectResponseBody", msg))
+
+	return resp
 
     def soap_RequestAccess(self, ps, fid):
Index: fedd/fedd_types.xsd
===================================================================
--- fedd/fedd_types.xsd	(revision 7da9da6d3e2f324bb49a9b9403f751554663dd86)
+++ fedd/fedd_types.xsd	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -118,5 +118,5 @@
     </xsd:annotation>
     <xsd:sequence>
-      <xsd:element name="name" type="tns:IDType"/>
+      <xsd:element name="name" type="tns:IDType" minOccurs="0" maxOccurs="1"/>
       <xsd:element name="user" type="tns:userType" minOccurs="0"
 	maxOccurs="unbounded"/>
@@ -152,4 +152,15 @@
       <xsd:element name="resources" type="tns:resourcesType" 
 	minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="projectAllocResponseType">
+    <xsd:annotation>
+      <xsd:documentation>
+	The information needed to create a dynamic project
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="project" type="tns:projectType"/>
     </xsd:sequence>
   </xsd:complexType>
Index: fedd/fedd_util.py
===================================================================
--- fedd/fedd_util.py	(revision 7da9da6d3e2f324bb49a9b9403f751554663dd86)
+++ fedd/fedd_util.py	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -181,5 +181,9 @@
     """
     if getattr(contents, "__iter__", None) != None:
-	obj = getattr(container, "new_%s" % name, None)()
+	try:
+	    obj = getattr(container, "new_%s" % name, None)()
+	except:
+	    print "%s has no method new_%s" % (container, name)
+	    raise
 	for e, v in contents.iteritems():
 	    assign = getattr(obj, "set_element_%s" % e, None) or \
Index: fedd/service_error.py
===================================================================
--- fedd/service_error.py	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
+++ fedd/service_error.py	(revision ef36c1e4429d847438bddbe74144191fea6073a5)
@@ -0,0 +1,42 @@
+#!/usr/local/bin/python
+
+# This is used to make the service error reporting independent of the
+# transport.  The XMLRPC and SOAP dispatchers will convert it into
+# transport-specific errors
+class service_error(RuntimeError):
+    access = 1
+    proxy= 2
+    req = 3
+    server_config = 4
+    internal = 5
+    code_str = { 
+	access : "Access Denied",
+	proxy : "Proxy Error",
+	req : "Badly Formed Request",
+	server_config: "Server Configuration Error",
+	internal : "Internal Error"
+    }
+    str_code = dict([ (v, k) for k, v in code_str.iteritems() ])
+    client_errors = ( req )
+    server_errors = ( access, proxy, server_config, internal)
+
+    def __init__(self, code=None, desc=None, from_string=None):
+	self.code = code
+	self.desc = desc
+	if code == None:
+	    self.set_code_from_string(from_string)
+	RuntimeError.__init__(self, desc)
+
+    def code_string(self, code=None):
+	code = code or self.code
+	return service_error.code_str.get(code)
+    
+    def set_code_from_string(self, errstr):
+	self.code = service_error.str_code.get(errstr, service_error.internal)
+	return self.code
+    
+    def is_client_error(self):
+	return self.code in service_error.client_errors
+
+    def is_server_error(self):
+	return self.code in service_error.server_errors
