Index: fedd/federation/allocate_project.py
===================================================================
--- fedd/federation/allocate_project.py	(revision 5a6b75bbe1bec02b8f74e27e2b7cb18a6e30866f)
+++ fedd/federation/allocate_project.py	(revision 08329f42d25f6f1a2825be5faaf26196e80961cd)
@@ -10,5 +10,5 @@
 from util import *
 from fedid import fedid
-from fixed_resource import read_key_db, read_project_db
+from fixed_resource import read_key_db, read_project_db, read_user_db
 from remote_service import xmlrpc_handler, soap_handler, service_caller
 from service_error import service_error
@@ -56,4 +56,8 @@
 	self.rmproj = config.get('allocate', 'rmproj',
 		'/usr/testbed/sbin/rmproj')
+	self.rmuser = config.get('allocate', 'rmuser',
+		'/usr/testbed/sbin/rmuser')
+	self.newuser = config.get('allocate', 'newuser',
+		'/usr/testbed/sbin/newuser')
 	self.addpubkey = config.get('allocate', 'addpubkey', 
 		'/usr/testbed/sbin/taddpubkey')
@@ -62,4 +66,6 @@
 	self.confirmkey = config.get('allocate', 'confirmkey', 
 		'/usr/testbed/sbin/taddpubkey')
+	self.user_to_project=config.get("allocate", 'user_to_project',
+		'/usr/local/bin/user_to_project.py')
 	self.allocation_level = config.get("allocate", "allocation_level", 
 		"none")
@@ -94,11 +100,14 @@
 	fixed_key_db = config.get("allocate", "fixed_keys", None)
 	fixed_project_db = config.get("allocate", "fixed_projects", None)
+	fixed_user_db = config.get("allocate", "fixed_users", None)
 	self.fixed_keys = set()
 	self.fixed_projects = set()
+	self.fixed_users = set()
 
 	# initialize the fixed resource sets
 	for db, rset, fcn in (\
 		(fixed_key_db, self.fixed_keys, read_key_db), \
-		(fixed_project_db, self.fixed_projects, read_project_db)):
+		(fixed_project_db, self.fixed_projects, read_project_db),
+		(fixed_user_db, self.fixed_users, read_user_db)):
 	    if db:
 		try:
@@ -160,5 +169,7 @@
 			    "permitted: check allocation level")
 	# tempfiles for the parameter files
-	uf, userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
+	cuf, create_userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
+		dir="/tmp")
+	suf, service_userfile = tempfile.mkstemp(prefix="usr", suffix=".xml",
 		dir="/tmp")
 	pf, projfile = tempfile.mkstemp(prefix="proj", suffix=".xml",
@@ -173,34 +184,46 @@
 	# Take the first user and ssh key
 	name = proj.get('name', None) or self.random_string("proj",4)
-	user = proj.get('user', None)
-	if user != None:
-	    user = user[0]	# User is a list, take the first entry
-	    if not user.has_key("userID"):
-		uname = self.random_string("user", 3)
-	    else:
-		uid = proj['userID']
-		# XXX: fedid
-		uname = uid.get('localname', None) or \
+	user = proj.get('user', [])
+
+	uname = { }
+	ssh = { }
+	for u in user:
+	    role = u.get('role', None)
+	    if not role: continue
+	    if u.has_key('userID'):
+		uid = u['userID']
+		uname[role] = uid.get('localname', None) or \
 			uid.get('kerberosUsername', None) or \
 			uid.get('uri', None)
-		if uname == None:
-		    raise service_error(service_error.req, "No ID for user");
-
-	    access = user.get('access', None)
-	    if access != None:
-		ssh = access[0].get('sshPubkey', None)
-		if ssh == None:
-		    raise service_error(service_error.req, 
-			    "No ssh key for user");
-	else:
-	    raise service_error(service_error.req, 
-		    "No access information for project");
-
-	# uname, name and ssh are set
-	user_fields = [
-		("name", "Federation User %s" % uname),
-		("email", "%s-fed@isi.deterlab.net" % uname),
+		if uname[role] == None:
+		    raise service_error(service_error.req, "No ID for user")
+	    else:
+		uname[role] = self.random_string("user", 3)
+
+	    access = u.get('access', None)
+	    if access:
+		# XXX collect and call addpubkey later, for now use first one.
+		for a in access:
+		    ssh[role] = a.get('sshPubkey', None)
+		    if ssh: break
+		else:
+		    raise service_error(service_error.req,
+			    "No SSH key for user %s" % uname[role])
+	    else:
+		raise service_error(service_error.req,
+			"No access mechanisms for for user %s" % uname[role])
+
+	if not (uname.has_key('experimentCreation') and \
+		uname.has_key('serviceAccess')):
+	    raise service_error(service_error.req,
+		    "Must specify both user roles")
+	
+
+	create_user_fields = [
+		("name", "Federation User %s" % uname['experimentCreation']),
+		("email", "%s-fed@isi.deterlab.net" % \
+			uname['experimentCreation']),
 		("password", self.random_string("", 8)),
-		("login", uname),
+		("login", uname['experimentCreation']),
 		("address", "4676 Admiralty"),
 		("city", "Marina del Rey"),
@@ -211,5 +234,21 @@
 		("title", "None"),
 		("affiliation", "USC/ISI"),
-		("pubkey", ssh)
+		("pubkey", ssh['experimentCreation'])
+	]
+
+	service_user_fields = [
+		("name", "Federation User %s" % uname['serviceAccess']),
+		("email", "%s-fed@isi.deterlab.net" % uname['serviceAccess']),
+		("password", self.random_string("", 8)),
+		("login", uname['serviceAccess']),
+		("address", "4676 Admiralty"),
+		("city", "Marina del Rey"),
+		("state", "CA"),
+		("zip", "90292"),
+		("country", "USA"),
+		("phone", "310-448-9190"),
+		("title", "None"),
+		("affiliation", "USC/ISI"),
+		("pubkey", ssh['serviceAccess'])
 	]
 
@@ -223,10 +262,11 @@
 		("num_pcs", "100"),
 		("linkedtous", "1"),
-		("newuser_xml", userfile)
+		("newuser_xml", create_userfile)
 	]
 	
 
 	# Write out the files
-	self.write_attr_xml(uf, "user", user_fields)
+	self.write_attr_xml(cuf, "user", create_user_fields)
+	self.write_attr_xml(suf, "user", service_user_fields)
 	self.write_attr_xml(pf, "project", proj_fields)
 
@@ -234,5 +274,7 @@
 	cmds = [
 		(self.wap, self.newproj, projfile),
-		(self.wap, self.mkproj, name)
+		(self.wap, self.mkproj, name),
+		(self.wap, self.newuser, service_userfile),
+		(self.wap, self.user_to_project, uname['serviceAccess'], name),
 		]
 
@@ -260,13 +302,22 @@
 				"[%s] (%d)" % (cmd[1], rc))
 	# Clean up tempfiles
-	os.unlink(userfile)
-	os.unlink(projfile)
+	#os.unlink(create_userfile)
+	#os.unlink(service_userfile)
+	#os.unlink(projfile)
 	rv = {\
 	    'project': {\
 		'name': { 'localname': name }, 
-		'user' : [ {\
-		    'userID': { 'localname' : uname },
-		    'access': [ { 'sshPubkey' : ssh } ],
-		} ]\
+		'user' : [\
+		    {\
+			'userID': { 'localname' : uname['experimentCreation'] },
+			'access': [ {'sshPubkey': ssh['experimentCreation'] } ],
+			'role': 'experimentCreation',
+		    }, \
+		    {\
+			'userID': { 'localname' : uname['serviceAccess'] },
+			'access': [ { 'sshPubkey' : ssh['serviceAccess'] } ], 
+			'role': 'serviceAccess',
+		    } \
+		]\
 	    }\
 	}
@@ -370,4 +421,8 @@
 	    raise service_error(service_error.req, "Badly formed request")
 
+	if pname and pname not in self.fixed_projects and \
+		self.allocation_level >= self.dynamic_projects:
+	    cmds.append((self.wap, self.rmproj, pname))
+
 	for u in users:
 	    try:
@@ -375,13 +430,14 @@
 	    except KeyError:
 		raise service_error(service_error.req, "Badly formed user")
-	    for sk in [ k['sshPubkey'] for k in u.get('access', []) \
-		    if k.has_key('sshPubkey')]:
-		if (name.rstrip(), sk.rstrip()) not in self.fixed_keys:
-		    if self.allocation_level >= self.dynamic_keys:
-			cmds.append((self.wap, self.addpubkey, '-R', '-w', \
-				'-u', name, '-k', sk))
-	if pname and pname not in self.fixed_projects and \
-		self.allocation_level >= self.dynamic_projects:
-	    cmds.append((self.wap, self.rmproj, pname))
+	    if self.allocation_level >= self.dynamic_projects and \
+		    name not in self.fixed_users:
+		cmds.append((self.wap, self.rmuser, name))
+	    else:
+		for sk in [ k['sshPubkey'] for k in u.get('access', []) \
+			if k.has_key('sshPubkey')]:
+		    if (name.rstrip(), sk.rstrip()) not in self.fixed_keys:
+			if self.allocation_level >= self.dynamic_keys:
+			    cmds.append((self.wap, self.addpubkey, '-R', '-w', \
+				    '-u', name, '-k', sk))
 
 	# Run the commands 
Index: fedd/federation/fixed_resource.py
===================================================================
--- fedd/federation/fixed_resource.py	(revision 5a6b75bbe1bec02b8f74e27e2b7cb18a6e30866f)
+++ fedd/federation/fixed_resource.py	(revision 08329f42d25f6f1a2825be5faaf26196e80961cd)
@@ -48,2 +48,5 @@
 	print >>f, "%s" % p
     f.close()
+
+read_user_db = read_project_db
+write_user_db = write_project_db
Index: fedd/user_to_group.py
===================================================================
--- fedd/user_to_group.py	(revision 08329f42d25f6f1a2825be5faaf26196e80961cd)
+++ fedd/user_to_group.py	(revision 08329f42d25f6f1a2825be5faaf26196e80961cd)
@@ -0,0 +1,43 @@
+#!/usr/local/bin/python
+
+import os, sys
+import MySQLdb
+from optparse import OptionParser
+
+if len(sys.argv) == 3:
+    user, project = sys.argv[1:3]
+else:
+    sys.exit("Usage %s user project" % sys.argv[0])
+
+db = MySQLdb.connect(db='tbdb')
+c = db.cursor()
+c.execute("select uid, uid_idx from users where uid=%s", (user,))
+
+uids = c.fetchall()
+
+if len(uids) == 1:
+    uid, uid_idx = uids[0]
+else:
+    sys.exit("User is not unique??")
+
+
+c.execute("select pid, pid_idx, gid_idx from groups where pid=%s and pid = gid", (project,))
+gids = c.fetchall()
+
+if len(gids) == 1:
+    pid, pid_idx, gid_idx = gids[0]
+else:
+    sys.exit("Group is not unique")
+
+c.execute("select uid from group_membership where uid=%s and pid=%s", (user, project))
+
+uids = c.fetchall()
+if len(uids) != 0:
+    sys.exit("%s already in %s" % (user, project))
+
+c.execute("insert into group_membership (uid, uid_idx, gid, gid_idx, pid, " + \
+	"pid_idx, trust, date_applied, date_approved) " + \
+	"values (%s, %s, %s, %s, %s, %s, 'none', now(), now())",
+	(uid, uid_idx, pid, gid_idx, pid, pid_idx))
+
+print "inserted %d rows" % c.rowcount
