Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 5e1fb7bf09cc613c00ede4fd0a144bb834bcba76)
+++ fedd/federation/emulab_access.py	(revision f771e2fb0197af667561fdefaf54abf04531475d)
@@ -14,4 +14,6 @@
 from M2Crypto.SSL import SSLError
 
+from access import access_base
+
 from util import *
 from allocate_project import allocate_project_local, allocate_project_remote
@@ -39,5 +41,5 @@
 fl.addHandler(nullHandler())
 
-class access:
+class access(access_base):
     """
     The implementation of access control based on mapping users to projects.
@@ -46,7 +48,4 @@
     dynamically.  This implements both direct requests and proxies.
     """
-
-    class parse_error(RuntimeError): pass
-
 
     proxy_RequestAccess= service_caller('RequestAccess')
@@ -58,20 +57,6 @@
         """
 
-	def software_list(v):
-	    l = [ ]
-	    if v:
-		ps = v.split(" ")
-		while len(ps):
-		    loc, file = ps[0:2]
-		    del ps[0:2]
-		    l.append((loc, file))
-	    return l
-
-
-        # Make sure that the configuration is in place
-        if not config: 
-            raise RunTimeError("No config to fedd.access")
-
-        self.project_priority = config.getboolean("access", "project_priority")
+	access_base.__init__(self, config, auth)
+
         self.allow_proxy = config.getboolean("access", "allow_proxy")
 
@@ -81,5 +66,4 @@
         self.fileserver = config.get("access", "fileserver")
         self.eventserver = config.get("access", "eventserver")
-	self.certdir = config.get("access","certdir")
 	self.userconfdir = config.get("access","userconfdir")
 	self.userconfcmd = config.get("access","userconfcmd")
@@ -94,7 +78,4 @@
 	self.ssh_pubkey_file = config.get("access","ssh_pubkey_file")
 	self.ssh_port = config.get("access","ssh_port") or "22"
-	self.create_debug = config.getboolean("access", "create_debug")
-	self.cleanup = not config.getboolean("access", "leave_tmpfiles")
-	self.access_type = config.get("access", "type")
 
 	self.dragon_endpoint = config.get("access", "dragon")
@@ -109,7 +90,7 @@
 	self.node_startcommand = config.get("access", "node_startcommand")
 
-	self.federation_software = software_list(self.federation_software)
-	self.portal_software = software_list(self.portal_software)
-	self.local_seer_software = software_list(self.local_seer_software)
+	self.federation_software = self.software_list(self.federation_software)
+	self.portal_software = self.software_list(self.portal_software)
+	self.local_seer_software = self.software_list(self.local_seer_software)
 
 	self.access_type = self.access_type.lower()
@@ -124,5 +105,4 @@
 	    self.stop_segment = None
 
-        self.access = { }
         self.restricted = [ ]
         self.projects = { }
@@ -136,13 +116,7 @@
             'types': self.types
         }
-        self.log = logging.getLogger("fedd.access")
-        set_log_level(config, "access", self.log)
-        self.state_lock = Lock()
-	# XXX: Configurable
-	self.exports = set(('SMB', 'seer', 'tmcd', 'userconfig', 
-	    'project_export', 'local_seer_control', 'seer_master', 
-	    'hide_hosts'))
-	self.imports = set(('SMB', 'seer', 'userconfig', 'seer_master',
-	    'hide_hosts'))
+        self.access = { }
+        if config.has_option("access", "accessdb"):
+            self.read_access(config.get("access", "accessdb"))
 
 	if not self.local_seer_image or not self.local_seer_software:
@@ -156,10 +130,4 @@
 	    self.exports.discard('seer_master')
 
-        if auth: self.auth = auth
-        else:
-            self.log.error(\
-                    "[access]: No authorizer initialized, creating local one.")
-            auth = authorizer()
-
         tb = config.get('access', 'testbed')
         if tb: self.testbed = [ t.strip() for t in tb.split(',') ]
@@ -167,19 +135,25 @@
 
         if config.has_option("access", "accessdb"):
-            self.read_access(config.get("access", "accessdb"))
-
-        self.state_filename = config.get("access", "access_state")
-        self.read_state()
-
-        # Keep cert_file and cert_pwd coming from the same place
-        self.cert_file = config.get("access", "cert_file")
-        if self.cert_file:
-            self.sert_pwd = config.get("access", "cert_pw")
-        else:
-            self.cert_file = config.get("globals", "cert_file")
-            self.sert_pwd = config.get("globals", "cert_pw")
-
-        self.trusted_certs = config.get("access", "trusted_certs") or \
-                config.get("globals", "trusted_certs")
+            self.read_access(config.get("access", "accessdb"), 
+		    self.make_access_project)
+
+	# read state in the base_class
+	self.state_lock.acquire()
+	self.allocation = self.state['allocation']
+	self.projects = self.state['projects']
+	self.keys = self.state['keys']
+	self.types = self.state['types']
+	# Add the ownership attributes to the authorizer.  Note that the
+	# indices of the allocation dict are strings, but the attributes are
+	# fedids, so there is a conversion.
+	for k in self.allocation.keys():
+	    for o in self.allocation[k].get('owners', []):
+		self.auth.set_attribute(o, fedid(hexstr=k))
+	    if self.allocation[k].has_key('userconfig'):
+		sfid = self.allocation[k]['userconfig']
+		fid = fedid(hexstr=sfid)
+		self.auth.set_attribute(fid, "/%s" % sfid)
+	self.state_lock.release()
+
 
         self.soap_services = {\
@@ -217,213 +191,28 @@
 
     @staticmethod
-    def add_kit(e, kit):
-	"""
-	Add a Software object created from the list of (install, location)
-	tuples passed as kit  to the software attribute of an object e.  We
-	do this enough to break out the code, but it's kind of a hack to
-	avoid changing the old tuple rep.
-	"""
-
-	s = [ topdl.Software(install=i, location=l) for i, l in kit]
-
-	if isinstance(e.software, list): e.software.extend(s)
-	else: e.software = s 
-
-
-    def read_access(self, config):
-        """
-        Read a configuration file and set internal parameters.
-
-        The format is more complex than one might hope.  The basic format is
-        attribute value pairs separated by colons(:) on a signle line.  The
-        attributes in bool_attrs, emulab_attrs and id_attrs can all be set
-        directly using the name: value syntax.  E.g. 
-        boss: hostname
-        sets self.boss to hostname.  In addition, there are access lines of the
-        form (tb, proj, user) -> (aproj, auser) that map the first tuple of
-        names to the second for access purposes.  Names in the key (left side)
-        can include "<NONE> or <ANY>" to act as wildcards or to require the
-        fields to be empty.  Similarly aproj or auser can be <SAME> or
-        <DYNAMIC> indicating that either the matching key is to be used or a
-        dynamic user or project will be created.  These names can also be
-        federated IDs (fedid's) if prefixed with fedid:.  Finally, the aproj
-        can be followed with a colon-separated list of node types to which that
-        project has access (or will have access if dynamic).
-        Testbed attributes outside the forms above can be given using the
-        format attribute: name value: value.  The name is a single word and the
-        value continues to the end of the line.  Empty lines and lines startin
-        with a # are ignored.
-
-        Parsing errors result in a self.parse_error exception being raised.
-        """
-        lineno=0
-        name_expr = "["+string.ascii_letters + string.digits + "\.\-_]+"
-        fedid_expr = "fedid:[" + string.hexdigits + "]+"
-        key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")"
-        access_proj = "(<DYNAMIC>(?::" + name_expr +")*|"+ \
-                "<SAME>" + "(?::" + name_expr + ")*|" + \
-                fedid_expr + "(?::" + name_expr + ")*|" + \
-                name_expr + "(?::" + name_expr + ")*)"
-        access_name = "(<DYNAMIC>|<SAME>|" + fedid_expr + "|"+ name_expr + ")"
-
-        restricted_re = re.compile("restricted:\s*(.*)", re.IGNORECASE)
-        access_re = re.compile('\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+
-                key_name+'\s*\)\s*->\s*\('+access_proj + '\s*,\s*' + 
-                access_name + '\s*,\s*' + access_name + '\s*\)', re.IGNORECASE)
-
+    def make_access_project(str):
         def parse_name(n):
             if n.startswith('fedid:'): return fedid(hexstr=n[len('fedid:'):])
             else: return n
-        
-        def auth_name(n):
-            if isinstance(n, basestring):
-                if n =='<any>' or n =='<none>': return None
-                else: return unicode(n)
-            else:
-                return n
-
-        f = open(config, "r");
-        for line in f:
-            lineno += 1
-            line = line.strip();
-            if len(line) == 0 or line.startswith('#'):
-                continue
-
-            # Restricted entry 
-            m = restricted_re.match(line)
-            if m != None:
-                val = m.group(1)
-                self.restricted.append(val)
-                continue
-
-            # Access line (t, p, u) -> (ap, cu, su) line
-            m = access_re.match(line)
-            if m != None:
-                access_key = tuple([ parse_name(x) for x in m.group(1,2,3)])
-                auth_key = tuple([ auth_name(x) for x in access_key])
-                aps = m.group(4).split(":");
-                if aps[0] == 'fedid:':
-                    del aps[0]
-                    aps[0] = fedid(hexstr=aps[0])
-
-                cu = parse_name(m.group(5))
-                su = parse_name(m.group(6))
-
-                access_val = (access_project(aps[0], aps[1:]),
-                        parse_name(m.group(5)), parse_name(m.group(6)))
-
-                self.access[access_key] = access_val
-                self.auth.set_attribute(auth_key, "access")
-                continue
-
-            # Nothing matched to here: unknown line - raise exception
-            f.close()
-            raise self.parse_error("Unknown statement at line %d of %s" % \
-                    (lineno, config))
-        f.close()
-
-    def get_users(self, obj):
-        """
-        Return a list of the IDs of the users in dict
-        """
-        if obj.has_key('user'):
-            return [ unpack_id(u['userID']) \
-                    for u in obj['user'] if u.has_key('userID') ]
-        else:
-            return None
-
-    def write_state(self):
-        if self.state_filename:
-            try:
-                f = open(self.state_filename, 'w')
-                pickle.dump(self.state, f)
-            except EnvironmentError, e:
-                self.log.error("Can't write file %s: %s" % \
-                        (self.state_filename, e))
-            except pickle.PicklingError, e:
-                self.log.error("Pickling problem: %s" % e)
-            except TypeError, e:
-                self.log.error("Pickling problem (TypeError): %s" % e)
-
-
-    def read_state(self):
-        """
-        Read a new copy of access state.  Old state is overwritten.
-
-        State format is a simple pickling of the state dictionary.
-        """
-        if self.state_filename:
-            try:
-                f = open(self.state_filename, "r")
-                self.state = pickle.load(f)
-
-                self.allocation = self.state['allocation']
-                self.projects = self.state['projects']
-                self.keys = self.state['keys']
-                self.types = self.state['types']
-
-                self.log.debug("[read_state]: Read state from %s" % \
-                        self.state_filename)
-            except EnvironmentError, e:
-                self.log.warning(("[read_state]: No saved state: " +\
-                        "Can't open %s: %s") % (self.state_filename, e))
-            except EOFError, e:
-                self.log.warning(("[read_state]: " +\
-                        "Empty or damaged state file: %s:") % \
-                        self.state_filename)
-            except pickle.UnpicklingError, e:
-                self.log.warning(("[read_state]: No saved state: " + \
-                        "Unpickling failed: %s") % e)
-
-            # Add the ownership attributes to the authorizer.  Note that the
-            # indices of the allocation dict are strings, but the attributes are
-            # fedids, so there is a conversion.
-            for k in self.allocation.keys():
-                for o in self.allocation[k].get('owners', []):
-                    self.auth.set_attribute(o, fedid(hexstr=k))
-		if self.allocation[k].has_key('userconfig'):
-		    sfid = self.allocation[k]['userconfig']
-		    fid = fedid(hexstr=sfid)
-		    self.auth.set_attribute(fid, "/%s" % sfid)
-
-
-    def permute_wildcards(self, a, p):
-        """Return a copy of a with various fields wildcarded.
-
-        The bits of p control the wildcards.  A set bit is a wildcard
-        replacement with the lowest bit being user then project then testbed.
-        """
-        if p & 1: user = ["<any>"]
-        else: user = a[2]
-        if p & 2: proj = "<any>"
-        else: proj = a[1]
-        if p & 4: tb = "<any>"
-        else: tb = a[0]
-
-        return (tb, proj, user)
-
-    def find_access(self, search):
-        """
-        Search the access DB for a match on this tuple.  Return the matching
-        access tuple and the user that matched.
-        
-        NB, if the initial tuple fails to match we start inserting wildcards in
-        an order determined by self.project_priority.  Try the list of users in
-        order (when wildcarded, there's only one user in the list).
-        """
-        if self.project_priority: perm = (0, 1, 2, 3, 4, 5, 6, 7)
-        else: perm = (0, 2, 1, 3, 4, 6, 5, 7)
-
-        for p in perm: 
-            s = self.permute_wildcards(search, p)
-            # s[2] is None on an anonymous, unwildcarded request
-            if s[2] != None:
-                for u in s[2]:
-                    if self.access.has_key((s[0], s[1], u)):
-                        return (self.access[(s[0], s[1], u)], u)
-            else:
-                if self.access.has_key(s):
-                    return (self.access[s], None)
-        return None, None
+
+	str = str.strip()
+	if str.startswith('(') and str.endswith(')'):
+	    str = str[1:-1]
+	    names = [ s.strip() for s in str.split(",")]
+	    if len(names) > 3:
+		raise self.parse_error("More than three fields in name")
+	    first = names[0].split(":")
+	    if first == 'fedid:':
+		del first[0]
+		first[0] = fedid(hexstr=first[0])
+	    names[0] = access_project(first[0], first[1:])
+
+	    for i in range(1,2):
+		names[i] = parse_name(names[i])
+
+	    return tuple(names)
+	else:
+	    raise self.parse_error('Bad mapping (unbalanced parens)')
+
 
     def lookup_access(self, req, fid):
@@ -434,68 +223,10 @@
         The fedid is needed to construct the request
         """
-	user_re = re.compile("user:\s(.*)")
-	project_re = re.compile("project:\s(.*)")
-
-        # Search keys
-        tb = None
-        project = None
-        user = None
         # Return values
         rp = access_project(None, ())
         ru = None
-
-	user = [ user_re.findall(x)[0] for x in req.get('credential', []) \
-		if user_re.match(x)]
-	project = [ project_re.findall(x)[0] \
-		for x in req.get('credential', []) \
-		    if project_re.match(x)]
-
-	if len(project) == 1: project = project[0]
-	elif len(project) == 0: project = None
-	else: 
-	    raise service_error(service_error.req, 
-		    "More than one project credential")
-
-
-        user_fedids = [ u for u in user if isinstance(u, fedid)]
-        # Determine how the caller is representing itself.  If its fedid shows
-        # up as a project or a singleton user, let that stand.  If neither the
-        # usernames nor the project name is a fedid, the caller is a testbed.
-        if project and isinstance(project, fedid):
-            if project == fid:
-                # The caller is the project (which is already in the tuple
-                # passed in to the authorizer)
-                owners = user_fedids
-                owners.append(project)
-            else:
-                raise service_error(service_error.req,
-                        "Project asserting different fedid")
-        else:
-            if fid not in user_fedids:
-                tb = fid
-                owners = user_fedids
-                owners.append(fid)
-            else:
-                if len(fedids) > 1:
-                    raise service_error(service_error.req,
-                            "User asserting different fedid")
-                else:
-                    # Which is a singleton
-                    owners = user_fedids
-        # Confirm authorization
-
-        for u in user:
-            self.log.debug("[lookup_access] Checking access for %s" % \
-                    ((tb, project, u),))
-            if self.auth.check_attribute((tb, project, u), 'access'):
-                self.log.debug("[lookup_access] Access granted")
-                break
-            else:
-                self.log.debug("[lookup_access] Access Denied")
-        else:
-            raise service_error(service_error.access, "Access denied")
-
         # This maps a valid user to the Emulab projects and users to use
-        found, user_match = self.find_access((tb, project, user))
+        found, match = self.lookup_access_base(req, fid)
+	tb, project, user = match
         
         if found == None:
@@ -551,188 +282,101 @@
 
         return (rp, rcu, rsu), (dyn_create_user, dyn_service_user, dyn_proj),\
-                owners
-
-    def get_handler(self, path, fid):
-	self.log.info("Get handler %s %s" % (path, fid))
-	if self.auth.check_attribute(fid, path) and self.userconfdir:
-	    return ("%s/%s" % (self.userconfdir, path), "application/binary")
+                [ fid ]
+
+    def do_project_allocation(self, dyn, project, user):
+	"""
+	Call the project allocation routines and return the info.
+	"""
+	if dyn: 
+	    # Compose the dynamic project request 
+	    # (only dynamic, dynamic currently allowed)
+	    preq = { 'AllocateProjectRequestBody': \
+			{ 'project' : {\
+			    'user': [ \
+			    { \
+				'access': [ { 
+				    'sshPubkey': self.ssh_pubkey_file } ],
+				 'role': "serviceAccess",\
+			    }, \
+			    { \
+				'access': [ { 
+				    'sshPubkey': self.ssh_pubkey_file } ],
+				 'role': "experimentCreation",\
+			    }, \
+			    ], \
+			    }\
+			}\
+		    }
+	    return self.allocate_project.dynamic_project(preq)
 	else:
-	    return (None, None)
-
-    def export_userconf(self, project):
-	dev_null = None
-	confid, confcert = generate_fedid("test", dir=self.userconfdir, 
-		log=self.log)
-	conffilename = "%s/%s" % (self.userconfdir, str(confid))
-	cf = None
+	    preq = {'StaticProjectRequestBody' : \
+		    { 'project': \
+			{ 'name' : { 'localname' : project },\
+			  'user' : [ \
+			    {\
+				'userID': { 'localname' : user }, \
+				'access': [ { 
+				    'sshPubkey': self.ssh_pubkey_file } ],
+				'role': 'experimentCreation'\
+			    },\
+			    {\
+				'userID': { 'localname' : user}, \
+				'access': [ { 
+				    'sshPubkey': self.ssh_pubkey_file } ],
+				'role': 'serviceAccess'\
+			    },\
+			]}\
+		    }\
+	    }
+	    return self.allocate_project.static_project(preq)
+
+    def save_project_state(self, aid, ap, dyn, owners):
+	"""
+	Parse out and save the information relevant to the project created for
+	this experiment.  That info is largely in ap and owners.  dyn indicates
+	that the project was created dynamically.  Return the user and project
+	names.
+	"""
+	self.state_lock.acquire()
+	self.allocation[aid] = { }
 	try:
-	    cf = open(conffilename, "w")
-	    os.chmod(conffilename, stat.S_IRUSR | stat.S_IWUSR)
-	except EnvironmentError, e:
-	    raise service_error(service_error.internal, 
-		    "Cannot create user configuration data")
+	    pname = ap['project']['name']['localname']
+	except KeyError:
+	    pname = None
+
+	if dyn:
+	    if not pname:
+		self.state_lock.release()
+		raise service_error(service_error.internal,
+			"Misformed allocation response?")
+	    if pname in self.projects: self.projects[pname] += 1
+	    else: self.projects[pname] = 1
+	    self.allocation[aid]['project'] = pname
+	else:
+	    # sproject is a static project associated with this allocation.
+	    self.allocation[aid]['sproject'] = pname
+
+	self.allocation[aid]['keys'] = [ ]
 
 	try:
-	    dev_null = open("/dev/null", "a")
-	except EnvironmentError, e:
-	    self.log.error("export_userconf: can't open /dev/null: %s" % e)
-
-	cmd = "%s %s" % (self.userconfcmd, project)
-	conf = subprocess.call(cmd.split(" "),
-		stdout=cf, stderr=dev_null, close_fds=True)
-
-	self.auth.set_attribute(confid, "/%s" % str(confid))
-
-	return confid, confcert
-
-    def export_SMB(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'SMB',
-		'visibility': 'export',
-		'server': 'http://fs:139',
-		'fedAttr': [
-			{ 'attribute': 'SMBSHARE', 'value': 'USERS' },
-			{ 'attribute': 'SMBUSER', 'value': user },
-			{ 'attribute': 'SMBPROJ', 'value': project },
-		    ]
-		}
-
-    def export_seer(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'seer',
-		'visibility': 'export',
-		'server': 'http://control:16606',
-		}
-
-    def export_local_seer(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'local_seer_control',
-		'visibility': 'export',
-		'server': 'http://control:16606',
-		}
-
-    def export_seer_master(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'seer_master',
-		'visibility': 'export',
-		'server': 'http://seer-master:17707',
-		}
-
-    def export_tmcd(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'seer',
-		'visibility': 'export',
-		'server': 'http://boss:7777',
-		}
-
-    def export_userconfig(self, id, state, project, user, attrs):
-	if self.userconfdir and self.userconfcmd \
-		and self.userconfurl:
-	    cid, cert = self.export_userconf(project)
-	    state['userconfig'] = unicode(cid)
-	    return {
-		    'id': id,
-		    'name': 'userconfig',
-		    'visibility': 'export',
-		    'server': "%s/%s" % (self.userconfurl, str(cid)),
-		    'fedAttr': [
-			{ 'attribute': 'cert', 'value': cert },
-		    ]
-		    }
-	else:
-	    return None
-
-    def export_hide_hosts(self, id, state, project, user, attrs):
-	return {
-		'id': id, 
-		'name': 'hide_hosts',
-		'visibility': 'export',
-		'fedAttr': [ x for x in attrs \
-			if x.get('attribute', "") == 'hosts'],
-		}
-
-    def export_services(self, sreq, project, user):
-	exp = [ ]
-	state = { }
-	# XXX: Filthy shortcut here using http: so urlparse will give the right
-	# answers.
-	for s in sreq:
-	    sname = s.get('name', '')
-	    svis = s.get('visibility', '')
-	    sattrs = s.get('fedAttr', [])
-	    if svis == 'export':
-		if sname in self.exports:
-		    id = s.get('id', 'no_id')
-		    if sname == 'SMB':
-			exp.append(self.export_SMB(id, state, project, user,
-			    sattrs))
-		    elif sname == 'seer':
-			exp.append(self.export_seer(id, state, project, user,
-			    sattrs))
-		    elif sname == 'tmcd':
-			exp.append(self.export_tmcd(id, state, project, user,
-			    sattrs))
-		    elif sname == 'userconfig':
-			exp.append(self.export_userconfig(id, state,
-			    project, user, sattrs))
-		    elif sname == 'project_export':
-			exp.append(self.export_SMB(id, state, project, user,
-			    sattrs))
-			#exp.append(self.export_seer(id, state, project, user,
-			#sattrs))
-			exp.append(self.export_userconfig(id, state,
-			    project, user, sattrs))
-		    elif sname == 'local_seer_control':
-			exp.append(self.export_local_seer(id, state, project,
-			    user, sattrs))
-		    elif sname == 'seer_master':
-			exp.append(self.export_seer_master(id, state, project,
-			    user, sattrs))
-		    elif sname == 'hide_hosts':
-			exp.append(self.export_hide_hosts(id, state, project,
-			    user, sattrs))
-	return (exp, state)
-
-    def build_response(self, alloc_id, ap, services):
-        """
-        Create the SOAP response.
-
-        Build the dictionary description of the response and use
-        fedd_utils.pack_soap to create the soap message.  ap is the allocate
-        project message returned from a remote project allocation (even if that
-        allocation was done locally).
-        """
-        # Because alloc_id is already a fedd_services_types.IDType_Holder,
-        # there's no need to repack it
-        msg = { 
-                'allocID': alloc_id,
-		'fedAttr': [
-		    { 'attribute': 'domain', 'value': self.domain } , 
-		    { 'attribute': 'project', 'value': 
-			ap['project'].get('name', {}).get('localname', "???") },
-		]
-            }
-
-	if self.dragon_endpoint:
-	    msg['fedAttr'].append({'attribute': 'dragon',
-		'value': self.dragon_endpoint})
-	if self.deter_internal:
-	    print 'adding internal'
-	    msg['fedAttr'].append({'attribute': 'deter_internal',
-		'value': self.deter_internal})
-	else: print "internal: %s" % self.deter_internal
-	#XXX: ??
-	if self.dragon_vlans:
-	    msg['fedAttr'].append({'attribute': 'vlans',
-		'value': self.dragon_vlans})
-
-	if services:
-	    msg['service'] = services
-        return msg
+	    for u in ap['project']['user']:
+		uname = u['userID']['localname']
+		if u['role'] == 'experimentCreation':
+		    self.allocation[aid]['user'] = uname
+		for k in [ k['sshPubkey'] for k in u['access'] \
+			if k.has_key('sshPubkey') ]:
+		    kv = "%s:%s" % (uname, k)
+		    if self.keys.has_key(kv): self.keys[kv] += 1
+		    else: self.keys[kv] = 1
+		    self.allocation[aid]['keys'].append((uname, k))
+	except KeyError:
+	    self.state_lock.release()
+	    raise service_error(service_error.internal,
+		    "Misformed allocation response?")
+
+	self.allocation[aid]['owners'] = owners
+	self.write_state()
+	self.state_lock.release()
+	return (pname, uname)
 
     def RequestAccess(self, req, fid):
@@ -774,185 +418,48 @@
             raise service_error(service_error.req, "No request!?")
 
-        if req.has_key('destinationTestbed'):
-            dt = unpack_id(req['destinationTestbed'])
-
-        if dt == None or dt in self.testbed:
-            # Request for this fedd
-            found, dyn, owners = self.lookup_access(req, fid)
-            restricted = None
-            ap = None
-
-	    # if this includes a project export request and the exported
-	    # project is not the access project, access denied.
-	    if 'service' in req:
-		ep = get_export_project(req['service'])
-                if ep and ep != found[0].name:
-                    raise service_error(service_error.access,
-                            "Cannot export %s" % ep)
-
-	    # XXX
-            # Check for access to restricted nodes
-            if req.has_key('resources') and req['resources'].has_key('node'):
-                resources = req['resources']
-                restricted = [ gateway_hardware(t) for n in resources['node'] \
-                                if n.has_key('hardware') \
-                                    for t in n['hardware'] \
-                                        if gateway_hardware(t) \
-                                            in self.restricted ]
-                inaccessible = [ t for t in restricted \
-                                    if t not in found[0].node_types]
-                if len(inaccessible) > 0:
-                    raise service_error(service_error.access,
-                            "Access denied (nodetypes %s)" % \
-                            str(', ').join(inaccessible))
-	    # XXX
-
-	    # These were passed around before, but now are hidden from users
-	    # and configurators alike, beyond a configuration file entry.
-            create_ssh = [ self.ssh_pubkey_file ]
-            service_ssh = [ self.ssh_pubkey_file ]
-
-            if len(create_ssh) > 0 and len(service_ssh) >0: 
-                if dyn[1]: 
-                    # Compose the dynamic project request 
-                    # (only dynamic, dynamic currently allowed)
-                    preq = { 'AllocateProjectRequestBody': \
-                                { 'project' : {\
-                                    'user': [ \
-                                    { \
-                                        'access': [ { 'sshPubkey': s } \
-                                            for s in service_ssh ], 
-                                         'role': "serviceAccess",\
-                                    }, \
-                                    { \
-                                        'access': [ { 'sshPubkey': s } \
-                                            for s in create_ssh ], 
-                                         'role': "experimentCreation",\
-                                    }, \
-                                    ], \
-                                    }\
-                                }\
-                            }
-                    if restricted != None and len(restricted) > 0:
-                        preq['AllocateProjectRequestBody']['resources'] = \
-                             {'node': [ { 'hardware' :  [ h ] } \
-                                    for h in restricted ] } 
-                    ap = self.allocate_project.dynamic_project(preq)
-                else:
-                    preq = {'StaticProjectRequestBody' : \
-                            { 'project': \
-                                { 'name' : { 'localname' : found[0].name },\
-                                  'user' : [ \
-                                    {\
-                                        'userID': { 'localname' : found[1] }, \
-                                        'access': [ { 'sshPubkey': s } 
-                                            for s in create_ssh ],
-                                        'role': 'experimentCreation'\
-                                    },\
-                                    {\
-                                        'userID': { 'localname' : found[2] }, \
-                                        'access': [ { 'sshPubkey': s } 
-                                            for s in service_ssh ],
-                                        'role': 'serviceAccess'\
-                                    },\
-                                ]}\
-                            }\
-                    }
-                    if restricted != None and len(restricted) > 0:
-                        preq['StaticProjectRequestBody']['resources'] = \
-                            {'node': [ { 'hardware' :  [ h ] } \
-                                    for h in restricted ] } 
-                    ap = self.allocate_project.static_project(preq)
-            else:
-                raise service_error(service_error.req, 
-                        "SSH access parameters required")
-            # keep track of what's been added
-            allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
-            aid = unicode(allocID)
-
-            self.state_lock.acquire()
-            self.allocation[aid] = { }
-            try:
-                pname = ap['project']['name']['localname']
-            except KeyError:
-                pname = None
-
-            if dyn[1]:
-                if not pname:
-                    self.state_lock.release()
-                    raise service_error(service_error.internal,
-                            "Misformed allocation response?")
-                if self.projects.has_key(pname): self.projects[pname] += 1
-                else: self.projects[pname] = 1
-                self.allocation[aid]['project'] = pname
-	    else:
-		# sproject is a static project associated with this allocation.
-		self.allocation[aid]['sproject'] = pname
-
-            if ap.has_key('resources'):
-                if not pname:
-                    self.state_lock.release()
-                    raise service_error(service_error.internal,
-                            "Misformed allocation response?")
-                self.allocation[aid]['types'] = set()
-                nodes = ap['resources'].get('node', [])
-                for n in nodes:
-                    for h in n.get('hardware', []):
-                        if self.types.has_key((pname, h)):
-                            self.types[(pname, h)] += 1
-                        else:
-                            self.types[(pname, h)] = 1
-                        self.allocation[aid]['types'].add((pname,h))
-
-
-            self.allocation[aid]['keys'] = [ ]
-
-            try:
-                for u in ap['project']['user']:
-                    uname = u['userID']['localname']
-		    if u['role'] == 'experimentCreation':
-			self.allocation[aid]['user'] = uname
-                    for k in [ k['sshPubkey'] for k in u['access'] \
-                            if k.has_key('sshPubkey') ]:
-                        kv = "%s:%s" % (uname, k)
-                        if self.keys.has_key(kv): self.keys[kv] += 1
-                        else: self.keys[kv] = 1
-                        self.allocation[aid]['keys'].append((uname, k))
-            except KeyError:
-                self.state_lock.release()
-                raise service_error(service_error.internal,
-                        "Misformed allocation response?")
-
-            self.allocation[aid]['owners'] = owners
-	    services, svc_state = self.export_services(req.get('service',[]),
-		    pname, uname)
-	    # Store services state in global state
-	    for k, v in svc_state.items():
-		self.allocation[aid][k] = v
-            self.write_state()
-            self.state_lock.release()
-            for o in owners:
-                self.auth.set_attribute(o, allocID)
-	    try:
-		f = open("%s/%s.pem" % (self.certdir, aid), "w")
-		print >>f, alloc_cert
-		f.close()
-	    except EnvironmentError, e:
-		raise service_error(service_error.internal, 
-			"Can't open %s/%s : %s" % (self.certdir, aid, e))
-            resp = self.build_response({ 'fedid': allocID } , ap, services)
-            return resp
-        else:
-            if self.allow_proxy:
-                resp = self.proxy_RequestAccess.call_service(dt, req,
-                            self.cert_file, self.cert_pwd,
-                            self.trusted_certs)
-                if resp.has_key('RequestAccessResponseBody'):
-                    return resp['RequestAccessResponseBody']
-                else:
-                    return None
-            else:
-                raise service_error(service_error.access,
-                        "Access proxying denied")
+
+	found, dyn, owners = self.lookup_access(req, fid)
+	ap = None
+
+	# if this includes a project export request and the exported
+	# project is not the access project, access denied.
+	if 'service' in req:
+	    ep = get_export_project(req['service'])
+	    if ep and ep != found[0].name:
+		raise service_error(service_error.access,
+			"Cannot export %s" % ep)
+
+	if self.ssh_pubkey_file:
+	    ap = self.do_project_allocation(dyn[1], found[0].name, found[1])
+	else:
+	    raise service_error(service_error.internal, 
+		    "SSH access parameters required")
+	# keep track of what's been added
+	allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log)
+	aid = unicode(allocID)
+
+	pname, uname = self.save_project_state(aid, ap, dyn[1], owners)
+
+	services, svc_state = self.export_services(req.get('service',[]),
+		pname, uname)
+	self.state_lock.acquire()
+	# Store services state in global state
+	for k, v in svc_state.items():
+	    self.allocation[aid][k] = v
+	self.write_state()
+	self.state_lock.release()
+	# Give the owners the right to change this allocation
+	for o in owners:
+	    self.auth.set_attribute(o, allocID)
+	try:
+	    f = open("%s/%s.pem" % (self.certdir, aid), "w")
+	    print >>f, alloc_cert
+	    f.close()
+	except EnvironmentError, e:
+	    raise service_error(service_error.internal, 
+		    "Can't open %s/%s : %s" % (self.certdir, aid, e))
+	resp = self.build_access_response({ 'fedid': allocID } ,
+		ap, services)
+	return resp
 
     def ReleaseAccess(self, req, fid):
@@ -1070,187 +577,4 @@
                         "Access proxying denied")
 
-    def generate_portal_configs(self, topo, pubkey_base, secretkey_base, 
-	    tmpdir, master, lproj, leid, connInfo, services):
-
-	def conninfo_to_dict(key, info):
-	    """
-	    Make a cpoy of the connection information about key, and flatten it
-	    into a single dict by parsing out any feddAttrs.
-	    """
-
-	    rv = None
-	    for i in info:
-		if key == i.get('portal', "") or \
-			key in [e.get('element', "") \
-			for e in i.get('member', [])]:
-		    rv = i.copy()
-		    break
-
-	    else:
-		return rv
-
-	    if 'fedAttr' in rv:
-		for a in rv['fedAttr']:
-		    attr = a.get('attribute', "")
-		    val = a.get('value', "")
-		    if attr and attr not in rv:
-			rv[attr] = val
-		del rv['fedAttr']
-	    return rv
-
-	# XXX: un hardcode this
-	def client_null(f, s):
-	    print >>f, "Service: %s" % s['name']
-
-	def client_seer_master(f, s):
-	    print >>f, 'PortalAlias: seer-master';
-
-	def client_smb(f, s):
-	    print >>f, "Service: %s" % s['name']
-	    smbshare = None
-	    smbuser = None
-	    smbproj = None
-	    for a in s.get('fedAttr', []):
-		if a.get('attribute', '') == 'SMBSHARE':
-		    smbshare = a.get('value', None)
-		elif a.get('attribute', '') == 'SMBUSER':
-		    smbuser = a.get('value', None)
-		elif a.get('attribute', '') == 'SMBPROJ':
-		    smbproj = a.get('value', None)
-
-	    if all((smbshare, smbuser, smbproj)):
-		print >>f, "SMBshare: %s" % smbshare
-		print >>f, "ProjectUser: %s" % smbuser
-		print >>f, "ProjectName: %s" % smbproj
-
-	def client_hide_hosts(f, s):
-	    for a in s.get('fedAttr', [ ]):
-		if a.get('attribute', "") == 'hosts':
-		    print >>f, "Hide: %s" % a.get('value', "")
-
-	client_service_out = {
-		'SMB': client_smb,
-		'tmcd': client_null,
-		'seer': client_null,
-		'userconfig': client_null,
-		'project_export': client_null,
-		'seer_master': client_seer_master,
-		'hide_hosts': client_hide_hosts,
-	    }
-
-	def client_seer_master_export(f, s):
-	    print >>f, "AddedNode: seer-master"
-
-	def client_seer_local_export(f, s):
-	    print >>f, "AddedNode: control"
-
-	client_export_service_out = {
-		'seer_master': client_seer_master_export,
-		'local_seer_control': client_seer_local_export,
-	    }
-
-	def server_port(f, s):
-	    p = urlparse(s.get('server', 'http://localhost'))
-	    print >>f, 'port: remote:%s:%s:%s' % (p.port, p.hostname, p.port) 
-
-	def server_null(f,s): pass
-
-	def server_seer(f, s):
-	    print >>f, 'seer: True'
-
-	server_service_out = {
-		'SMB': server_port,
-		'tmcd': server_port,
-		'userconfig': server_null,
-		'project_export': server_null,
-		'seer': server_seer,
-		'seer_master': server_port,
-		'hide_hosts': server_null,
-	    }
-	# XXX: end un hardcode this
-
-
-	seer_out = False
-	client_out = False
-	mproj = None
-	mexp = None
-	control_gw = None
-	testbed = ""
-	# Create configuration files for the portals
-	for e in [ e for e in topo.elements \
-		if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
-	    myname = e.name
-	    type = e.get_attribute('portal_type')
-
-	    info = conninfo_to_dict(myname, connInfo)
-
-	    if not info:
-		raise service_error(service_error.req,
-			"No connectivity info for %s" % myname)
-
-	    peer = info.get('peer', "")
-	    ldomain = self.domain;
-	    ssh_port = info.get('ssh_port', 22)
-
-	    # Collect this for the client.conf file
-	    if 'masterexperiment' in info:
-		mproj, meid = info['masterexperiment'].split("/", 1)
-
-	    if type in ('control', 'both'):
-		testbed = e.get_attribute('testbed')
-		control_gw = myname
-
-	    active = info.get('active', 'False')
-
-	    cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
-	    tunnelconfig = self.tunnel_config
-	    try:
-		f = open(cfn, "w")
-		if active == 'True':
-		    print >>f, "active: True"
-		    print >>f, "ssh_port: %s" % ssh_port
-		    if type in ('control', 'both'):
-			for s in [s for s in services \
-				if s.get('name', "") in self.imports]:
-			    server_service_out[s['name']](f, s)
-
-		if tunnelconfig:
-		    print >>f, "tunnelip: %s" % tunnelconfig
-		print >>f, "peer: %s" % peer.lower()
-		print >>f, "ssh_pubkey: /proj/%s/exp/%s/tmp/%s" % \
-			(lproj, leid, pubkey_base)
-		print >>f, "ssh_privkey: /proj/%s/exp/%s/tmp/%s" % \
-			(lproj, leid, secretkey_base)
-		f.close()
-	    except EnvironmentError, e:
-		raise service_error(service_error.internal,
-			"Can't write protal config %s: %s" % (cfn, e))
-
-	# Done with portals, write the client config file.
-	try:
-	    f = open("%s/client.conf" % tmpdir, "w")
-	    if control_gw:
-		print >>f, "ControlGateway: %s.%s.%s%s" % \
-		    (myname.lower(), leid.lower(), lproj.lower(),
-			    ldomain.lower())
-	    for s in services:
-		if s.get('name',"") in self.imports and \
-			s.get('visibility','') == 'import':
-		    client_service_out[s['name']](f, s)
-		if s.get('name', '') in self.exports and \
-			s.get('visibility', '') == 'export' and \
-			s['name'] in client_export_service_out:
-		    client_export_service_out[s['name']](f, s)
-	    # Seer uses this.
-	    if mproj and meid:
-		print >>f, "ExperimentID: %s/%s" % (mproj, meid)
-	    # Better way...
-	    if testbed == master:
-		print >>f, "SEERBase: True"
-	    f.close()
-	except EnvironmentError, e:
-	    raise service_error(service_error.internal,
-		    "Cannot write client.conf: %s" %s)
-
     def generate_ns2(self, topo, expfn, softdir, master, connInfo):
 	class dragon_commands:
@@ -1394,89 +718,4 @@
 		    "Cannot write experiment file %s: %s" % (expfn,e))
 
-    def export_store_info(self, cf, proj, ename, connInfo):
-	"""
-	For the export requests in the connection info, install the peer names
-	at the experiment controller via SetValue calls.
-	"""
-
-	for c in connInfo:
-	    for p in [ p for p in c.get('parameter', []) \
-		    if p.get('type', '') == 'output']:
-
-		if p.get('name', '') == 'peer':
-		    k = p.get('key', None)
-		    surl = p.get('store', None)
-		    if surl and k and k.index('/') != -1:
-			value = "%s.%s.%s%s" % \
-				(k[k.index('/')+1:], ename, proj, self.domain)
-			req = { 'name': k, 'value': value }
-			self.log.debug("Setting %s to %s on %s" % \
-				(k, value, surl))
-			self.call_SetValue(surl, req, cf)
-		    else:
-			self.log.error("Bad export request: %s" % p)
-		elif p.get('name', '') == 'ssh_port':
-		    k = p.get('key', None)
-		    surl = p.get('store', None)
-		    if surl and k:
-			req = { 'name': k, 'value': self.ssh_port }
-			self.log.debug("Setting %s to %s on %s" % \
-				(k, self.ssh_port, surl))
-			self.call_SetValue(surl, req, cf)
-		    else:
-			self.log.error("Bad export request: %s" % p)
-		else:
-		    self.log.error("Unknown export parameter: %s" % \
-			    p.get('name'))
-		    continue
-
-    def import_store_info(self, cf, connInfo):
-	"""
-	Pull any import parameters in connInfo in.  We translate them either
-	into known member names or fedAddrs.
-	"""
-
-	for c in connInfo:
-	    for p in [ p for p in c.get('parameter', []) \
-		    if p.get('type', '') == 'input']:
-		name = p.get('name', None)
-		key = p.get('key', None)
-		store = p.get('store', None)
-
-		if name and key and store :
-		    req = { 'name': key, 'wait': True }
-		    self.log.debug("Waiting for %s (%s) from %s" % \
-			    (name, key, store))
-		    r = self.call_GetValue(store, req, cf)
-		    r = r.get('GetValueResponseBody', None)
-		    if r :
-			if r.get('name', '') == key:
-			    v = r.get('value', None)
-			    if v is not None:
-				if name == 'peer':
-				    self.log.debug("Got peer %s" % v)
-				    c['peer'] = v
-				else:
-				    self.log.debug("Got %s %s" % (name, v))
-				    if c.has_key('fedAttr'):
-					c['fedAttr'].append({
-					    'attribute': name, 'value': v})
-				    else:
-					c['fedAttr']= [{
-					    'attribute': name, 'value': v}]
-			    else:
-				raise service_error(service_error.internal, 
-					'None value exported for %s'  % key)
-			else:
-			    raise service_error(service_error.internal, 
-				    'Different name returned for %s: %s' \
-					    % (key, r.get('name','')))
-		    else:
-			raise service_error(service_error.internal, 
-			    'Badly formatted response: no GetValueResponseBody')
-		else:
-		    raise service_error(service_error.internal, 
-			'Bad Services missing info for import %s' % c)
-
     def configure_userconf(self, services):
 	"""
