Index: fedd/federation/access.py
===================================================================
--- fedd/federation/access.py	(revision 353db8cf818f61d7d34c74ad0449f921d11ffa52)
+++ fedd/federation/access.py	(revision 6e635134e61a8acc84beb7576738e3839093e8fc)
@@ -194,4 +194,40 @@
 	finally:
 	    if f: f.close()
+
+    def read_abac_access(self, fn, access_obj=None):
+	"""
+	Read an access DB of the form
+	    abac.attribute -> local_auth_data
+	The access dict is filled with mappings from the abac attributes (as
+	strings) to the access objects.  The objects are strings by default,
+	but the class constructor is called with the string following the ->
+	and whitespace in the file.
+	"""
+
+	map_re = re.compile("(\S+)\s+->\s+(.*)");
+	if access_obj is None:
+	    access_obj = lambda(x): "%s" % x
+
+	f = open(fn, 'r')
+	try:
+	    lineno = 0
+	    for line in f:
+		lineno += 1
+		line = line.strip();
+		if len(line) == 0 or line.startswith('#'):
+		    continue
+		m = map_re.match(line)
+		if m != None:
+		    self.access[m.group(1)] = access_obj(m.group(2))
+		    continue
+
+		# Nothing matched to here: unknown line - raise exception
+		# (finally will close f)
+		raise self.parse_error(
+			"Unknown statement at line %d of %s" % \
+			(lineno, fn))
+	finally:
+	    if f: f.close()
+
 
     def get_users(self, obj):
Index: fedd/federation/authorizer.py
===================================================================
--- fedd/federation/authorizer.py	(revision 353db8cf818f61d7d34c74ad0449f921d11ffa52)
+++ fedd/federation/authorizer.py	(revision 6e635134e61a8acc84beb7576738e3839093e8fc)
@@ -192,6 +192,6 @@
     bad_name = authorizer_base.bad_name
     attribute_error = authorizer_base.attribute_error
-    class no_file(RuntimeError): pass
-    class bad_cert(RuntimeError): pass
+    class no_file_error(RuntimeError): pass
+    class bad_cert_error(RuntimeError): pass
 
     def __init__(self, certs=None, me=None, key=None, load=None, save=None):
@@ -203,5 +203,5 @@
 	# If the me parameter is a combination certificate, split it into the
 	# abac_authorizer save directory (if any) for use with creddy.
-	if abac_pem_type(self.me) == 'both':
+	if self.me is not None and abac_pem_type(self.me) == 'both':
 	    if self.save_dir:
 		self.key, self.me = abac_split_cert(self.me,
@@ -209,6 +209,6 @@
 			certfile = "%s/cert.pem" % self.save_dir)
 	    else:
-		raise abac_authorizer.bad_cert("Combination certificate " + \
-			"and nowhere to split it");
+		raise abac_authorizer.bad_cert_error("Combination " + \
+			"certificate and nowhere to split it");
 	else:
 	    self.key = key
Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 353db8cf818f61d7d34c74ad0449f921d11ffa52)
+++ fedd/federation/emulab_access.py	(revision 6e635134e61a8acc84beb7576738e3839093e8fc)
@@ -21,5 +21,5 @@
 from access_project import access_project
 from fedid import fedid, generate_fedid
-from authorizer import authorizer
+from authorizer import authorizer, abac_authorizer
 from service_error import service_error
 from remote_service import xmlrpc_handler, soap_handler, service_caller
@@ -105,13 +105,27 @@
         self.restricted = [ ]
         self.access = { }
-        if config.has_option("access", "accessdb"):
-            self.read_access(config.get("access", "accessdb"))
+	# XXX: this should go?
+        #if config.has_option("access", "accessdb"):
+        #    self.read_access(config.get("access", "accessdb"))
         tb = config.get('access', 'testbed')
         if tb: self.testbed = [ t.strip() for t in tb.split(',') ]
         else: self.testbed = [ ]
 
-        if config.has_option("access", "accessdb"):
-            self.read_access(config.get("access", "accessdb"), 
-		    self.make_access_project)
+	# authorization information
+	self.auth_type = config.get('access', 'auth_type') \
+		or 'legacy'
+	self.auth_dir = config.get('access', 'auth_dir')
+	accessdb = config.get("access", "accessdb")
+	# initialize the authorization system
+	if self.auth_type == 'legacy':
+	    if accessdb:
+		self.read_access(accessdb, self.make_access_project)
+	elif self.auth_type == 'abac':
+	    self.auth = abac_authorizer(load=self.auth_dir)
+	    if accessdb:
+		self.read_abac_access(accessdb, self.make_abac_access_project)
+	else:
+	    raise service_error(service_error.internal, 
+		    "Unknown auth_type: %s" % self.auth_type)
 
 	# read_state in the base_class
@@ -124,14 +138,15 @@
 	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)
+	if self.auth_type == "legacy": 
+	    # 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.exports = {
@@ -220,4 +235,21 @@
 	else:
 	    raise self.parse_error('Bad mapping (unbalanced parens)')
+
+    @staticmethod
+    def make_abac_access_project(str):
+	"""
+	Convert a string of the form (id, id) into an access_project.  This is
+	called by read_abac_access to convert to local attributes.  It returns
+	a tuple of the form (project, user, user) where the two users are
+	always the same.
+	"""
+
+	str = str.strip()
+	if str.startswith('(') and str.endswith(')') and str.count(',') == 1:
+	    proj, user = str.split(',')
+	    return ( proj.strip(), user.strip(), user.strip())
+	else:
+	    raise self.parse_error(
+		    'Bad mapping (unbalanced parens or more than 1 comma)')
 
 
@@ -296,4 +328,22 @@
                 [ fid ]
 
+    def lookup_abac_access(self, req, fid): 
+	# Import request credentials into this (clone later??)
+	if self.auth.import_credentials(data_list=req.get('abac_credential', [])):
+	    self.auth.save()
+
+	# Check every attribute that we know how to map and take the first
+	# success.
+	for attr in (self.access.keys()):
+	    if self.auth.check_attribute(fid, attr):
+		# XXX: needs to deal with dynamics
+		return copy.copy(self.access[attr]), (False, False, False), \
+			[ fid ]
+	    else:
+		self.log.debug("Access failed for %s %s" % (attr, fid))
+	else:
+            raise service_error(service_error.access, "Access denied")
+
+
     def do_project_allocation(self, dyn, project, user):
 	"""
@@ -433,5 +483,11 @@
 
 
-	found, dyn, owners = self.lookup_access(req, fid)
+	if self.auth_type == "legacy":
+	    found, dyn, owners = self.lookup_access(req, fid)
+	elif self.auth_type == 'abac':
+	    found, dyn, owners = self.lookup_abac_access(req, fid)
+	else:
+	    raise service_error(service_error.internal, 
+		    'Unknown auth_type: %s' % self.auth_type)
 	ap = None
 
@@ -466,4 +522,5 @@
 	for o in owners:
 	    self.auth.set_attribute(o, allocID)
+	self.auth.save()
 	try:
 	    f = open("%s/%s.pem" % (self.certdir, aid), "w")
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision 353db8cf818f61d7d34c74ad0449f921d11ffa52)
+++ fedd/federation/experiment_control.py	(revision 6e635134e61a8acc84beb7576738e3839093e8fc)
@@ -1431,4 +1431,114 @@
 	    allocated[tb] = 1
 
+    def get_abac_access_to_testbeds(self, testbeds, fid, allocated, 
+	    tbparams, masters, tbmap):
+	for tb in testbeds:
+	    self.get_abac_access(tb, tbparams, fid, masters, tbmap)
+	    allocated[tb] = 1
+
+    def get_abac_access(self, tb, tbparams,fid, masters, tbmap):
+        """
+        Get access to testbed through fedd and set the parameters for that tb
+        """
+	def get_export_project(svcs):
+	    """
+	    Look through for the list of federated_service for this testbed
+	    objects for a project_export service, and extract the project
+	    parameter.
+	    """
+
+	    pe = [s for s in svcs if s.name=='project_export']
+	    if len(pe) == 1:
+		return pe[0].params.get('project', None)
+	    elif len(pe) == 0:
+		return None
+	    else:
+		raise service_error(service_error.req,
+			"More than one project export is not supported")
+
+        uri = tbmap.get(testbed_base(tb), None)
+        if not uri:
+            raise service_error(service_error.server_config, 
+                    "Unknown testbed: %s" % tb)
+
+	export_svcs = masters.get(tb,[])
+	import_svcs = [ s for m in masters.values() \
+		for s in m \
+		    if tb in s.importers ]
+
+	export_project = get_export_project(export_svcs)
+	# Compose the credential list so that IDs come before attributes
+	creds = set()
+	keys = set()
+	for c in self.auth.get_creds_for_principal(fid):
+	    keys.add(c.issuer_cert())
+	    creds.add(c.attribute_cert())
+	creds = list(keys) + list(creds)
+
+	# Request credentials
+	req = {
+		'abac_credential': creds,
+	    }
+	# Make the service request from the services we're importing and
+	# exporting.  Keep track of the export request ids so we can
+	# collect the resulting info from the access response.
+	e_keys = { }
+	if import_svcs or export_svcs:
+	    req['service'] = [ ]
+
+	    for i, s in enumerate(import_svcs):
+		idx = 'import%d' % i
+		sr = {'id': idx, 'name': s.name, 'visibility': 'import' }
+		if s.params:
+		    sr['fedAttr'] = [ { 'attribute': k, 'value': v } \
+			    for k, v in s.params.items()]
+		req['service'].append(sr)
+
+	    for i, s in enumerate(export_svcs):
+		idx = 'export%d' % i
+		e_keys[idx] = s
+		sr = {'id': idx, 'name': s.name, 'visibility': 'export' }
+		if s.params:
+		    sr['fedAttr'] = [ { 'attribute': k, 'value': v } 
+			    for k, v in s.params.items()]
+		req['service'].append(sr)
+
+
+	if self.local_access.has_key(uri):
+	    # Local access call
+	    req = { 'RequestAccessRequestBody' : req }
+	    r = self.local_access[uri].RequestAccess(req, 
+		    fedid(file=self.cert_file))
+	    r = { 'RequestAccessResponseBody' : r }
+	else:
+	    r = self.call_RequestAccess(uri, req, 
+		    self.cert_file, self.cert_pwd, self.trusted_certs)
+
+	tbparam[tb] = { 
+		"allocID" : r['allocID'],
+		"uri": uri,
+		}
+
+	# Collect the responses corresponding to the services this testbed
+	# exports.  These will be the service requests that we will include in
+	# the start segment requests (with appropriate visibility values) to
+	# import and export the segments.
+	for s in r.get('service', []):
+	    id = s.get('id', None)
+	    if id and id in e_keys:
+		e_keys[id].reqs.append(s)
+
+	# Add attributes to parameter space.  We don't allow attributes to
+	# overlay any parameters already installed.
+	for a in r.get('fedAttr', []):
+	    try:
+		if a['attribute'] and \
+			isinstance(a['attribute'], basestring)\
+			and not tbparam[tb].has_key(a['attribute'].lower()):
+		    tbparam[tb][a['attribute'].lower()] = a['value']
+	    except KeyError:
+		self.log.error("Bad attribute in response: %s" % a)
+
+
     def split_topology(self, top, topo, testbeds):
 	"""
@@ -1637,4 +1747,8 @@
             raise service_error(service_error.req, "No request?")
 
+	# Import information from the requester
+	if self.auth.import_credentials(data_list=req.get('credential', [])):
+	    self.auth.save()
+
         self.check_experiment_access(fid, key)
 
@@ -1790,6 +1904,13 @@
 	    connInfo = { }	    # Connection information
 
-	    self.get_access_to_testbeds(testbeds, access_user, allocated, 
-		    tbparams, masters, tbmap)
+	    if self.auth_type == 'legacy':
+		self.get_access_to_testbeds(testbeds, access_user, allocated, 
+			tbparams, masters, tbmap)
+	    elif self.auth_type == 'abac':
+		self.get_abac_access_to_testbeds(testbeds, fid, allocated, 
+			tbparams, masters, tbmap)
+	    else:
+		raise service_error(service_error.internal, 
+			"Unknown auth_type %s" % self.auth_type)
 
 	    self.split_topology(top, topo, testbeds)
Index: fedd/federation/util.py
===================================================================
--- fedd/federation/util.py	(revision 353db8cf818f61d7d34c74ad0449f921d11ffa52)
+++ fedd/federation/util.py	(revision 6e635134e61a8acc84beb7576738e3839093e8fc)
@@ -10,4 +10,5 @@
 
 from socket import sslerror
+from tempfile import mkstemp
 
 from M2Crypto import SSL
@@ -267,4 +268,5 @@
     cert_re = re.compile('\s*-----BEGIN CERTIFICATE-----$') 
     type = None
+    print cert
     f = open(cert, 'r')
     for line in f:
@@ -290,14 +292,18 @@
 	'''
 	Wraps up the reqular expression to start and end a diversion, as well as
-	the open file that gets the lines.
+	the open file that gets the lines.  If fd is passed in, use that system
+	file (probably from a mkstemp.  Otherwise open the given filename.
 	'''
-	def __init__(self, start, end, fn):
+	def __init__(self, start, end, fn=None, fd=None):
 	    self.start = re.compile(start)
 	    self.end = re.compile(end)
-	    # Open the file securely with minimal permissions. NB file cannot
-	    # exist before this call.
-	    self.f = os.fdopen(os.open(fn,
-		(os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_EXCL), 0600),
-		'w')
+
+	    if not fd:
+		# Open the file securely with minimal permissions. NB file
+		# cannot exist before this call.
+		fd = os.open(fn,
+		    (os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_EXCL), 0600)
+
+	    self.f = os.fdopen(fd, 'w')
 
 	def close(self):
@@ -305,18 +311,21 @@
 
     if not keyfile:
-	f, keyfile = mkstemp(suffix=".pem")
-	os.close(f);
+	kf, rkeyfile = mkstemp(suffix=".pem")
+    else:
+	kf, rkeyfile = None, keyfile
+
     if not certfile:
-	f, certfile = mkstemp(suffix=".pem")
-	os.close(f);
+	cf, rcertfile = mkstemp(suffix=".pem")
+    else:
+	cf, rcertfile = None, certfile
 
     # Initialize the diversions
-    divs = [diversion(s, e, fn) for s, e,fn in (
+    divs = [diversion(s, e, fn=pfn, fd=pfd ) for s, e, pfn, pfd in (
 	('\s*-----BEGIN RSA PRIVATE KEY-----$', 
 	    '\s*-----END RSA PRIVATE KEY-----$',
-	    keyfile),
+	    keyfile, kf),
 	('\s*-----BEGIN CERTIFICATE-----$', 
 	    '\s*-----END CERTIFICATE-----$',
-	    certfile))]
+	    certfile, cf))]
 
     # walk through the file, beginning a diversion when a start regexp
@@ -340,5 +349,5 @@
     # This is probably unnecessary.  Close all the diversion files.
     for d in divs: d.close()
-    return keyfile, certfile
+    return rkeyfile, rcertfile
 
 def find_pickle_problem(o, st=None):
