Index: fedd/fedd_to_user_certs.py
===================================================================
--- fedd/fedd_to_user_certs.py	(revision 45016aef3242f33086944345f268fc1181648aca)
+++ fedd/fedd_to_user_certs.py	(revision 45016aef3242f33086944345f268fc1181648aca)
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+
+import sys
+import re
+
+import os
+import os.path
+import zipfile
+
+from tempfile import mkdtemp
+
+import Creddy
+
+from federation.authorizer import abac_authorizer
+from federation.util import abac_pem_type, abac_split_cert, file_expanding_opts
+
+class Parser(file_expanding_opts):
+    def __init__(self):
+	file_expanding_opts.__init__(self)
+	self.add_option('--cert', dest='cert', default=None,
+		action='callback', callback=self.expand_file, type='str',
+		help='my fedid as an X.509 certificate')
+	self.add_option('--key', dest='key', default=None,
+		action='callback', callback=self.expand_file, type='str',
+		help='key for the certificate')
+	self.add_option('--dir', dest='dir', default='.',
+		action='callback', callback=self.expand_file, type='str',
+		help='Output directory for credentials')
+	self.add_option('--make_dir', action='store_true', dest='make_dir',
+		default=False, help='Create the --dir directory')
+	self.add_option('--debug', action='store_true', dest='debug',
+		default=False, help='Just print the libcreddy parameters')
+	self.add_option('--user', action='append', dest='users',
+		help='Output credentials for this user.  ' + \
+			'May be specified more than once or omitted entirely')
+
+class identity:
+    def __init__(self, name, roles=None):
+	self.name = name
+	if roles: self.roles = set(roles)
+
+    def add_roles(self, roles):
+	self.roles |= set(roles)
+
+    def __str__(self):
+	return "%s: %s" % (self.name, ', '.join(self.roles))
+
+def clear_dir(dir):
+    '''
+    Empty the given directory (and all its subdirectories).
+    '''
+    for path, dirs, files in os.walk(dir, topdown=False):
+	for f in files: os.unlink(os.path.join(path, f))
+	for d in dirs: os.rmdir(os.path.join(path, d))
+
+def parse_configs(files):
+    """
+    Step through each file pulling the roles out of the database lines, if any,
+    and creating (or appending to) identity objects, one identity in a dict for
+    each  fedid.  Return that dict.  May raise an exception when file
+    difficulties occur.
+    """
+    comment_re = re.compile('^\s*#|^$')
+    fedid_str = 'fedid:([0-9a-fA-F]{40})'
+    id_str = '[a-zA-Z][\w/_-]*'
+    single_re = re.compile('\s*%s\s*->\s*(%s)' % (fedid_str, id_str))
+    double_re = re.compile('\s*%s\s*->\s*\((%s)\s*,\s*(%s)\)' % \
+	    (fedid_str, id_str, id_str))
+    bad_role = re.compile('[^a-zA-Z0-9_]+')
+
+    roles = { }
+
+    for fn in files:
+	f = open(fn, "r")
+	for l in f:
+	    id = None
+	    for r in (comment_re, single_re, double_re):
+		m = r.match(l)
+		if m: 
+		    # NB, the comment_re has no groups
+		    if m.groups():
+			g = m.groups()
+			id = g[0]
+			r = [ bad_role.sub('_', x) for x in g[1:] ]
+		    break
+	    else:
+		print 'Unmatched line: %s' % l 
+
+	    if id:
+		if id in roles: roles[id].add_roles(r)
+		else: roles[id] = identity(r[0], r)
+
+    return roles
+
+def make_credentials(roles, cert, key, creds_dir, users, debug):
+    """
+    From the dict of identities, indexed by fedid, call libcreddy to create the
+    ABAC certificates.  Return a list of the created files.  If debug is true,
+    just print the creddy attribute creation parameters.
+    """
+    credfiles = []
+    cwd = os.getcwd()
+    for k, id in roles.items():
+	if users is not None and id.name not in users:
+	    continue
+	if debug:
+	    print 'cert %s key %s role %s principal %s' % \
+		    (cert, key, ','.join(id.roles), k)
+	    continue
+
+	# This user is requested and we're not debugging
+
+	zname = os.path.join(creds_dir, '%s.zip' % id.name)
+	zf = zipfile.ZipFile(zname,'w', zipfile.ZIP_DEFLATED)
+	credfiles.append(zname)
+	td = mkdtemp()
+	try:
+	    os.chdir(td)
+	    cid = Creddy.ID(cert)
+	    cid.write_cert_name('issuer.pem')
+	    zf.write('issuer.pem')
+	    for i, r in enumerate(id.roles):
+		cf = '%s%03d_attr.der' % (id.name, i)
+		cid = Creddy.ID(cert)
+		cid.load_privkey(key)
+		cattr = Creddy.Attribute(cid, r, 3600 * 24 * 365 * 10)
+		cattr.principal(k)
+		cattr.bake()
+		cattr.write_name(cf)
+		zf.write(cf)
+	    os.chdir(cwd)
+	    zf.close()
+	finally:
+	    clear_dir(td)
+	    os.rmdir(td)
+
+    return credfiles
+
+# The main line
+
+parser = Parser()
+opts, args = parser.parse_args()
+cert, key = None, None
+delete_certs = False
+
+if opts.key:
+    if os.access(opts.key, os.R_OK): key = opts.key
+    else: sys.exit('Cannot read %s (key file)' % opts.key)
+
+if opts.users: users = set(opts.users)
+else: users = None
+
+creds_dir = opts.dir
+
+if opts.cert:
+    if os.access(opts.cert, os.R_OK):
+	if not key:
+	    if abac_pem_type(opts.cert) == 'both':
+		key, cert = abac_split_cert(opts.cert)
+		delete_certs = True
+	else:
+	    cert = opts.cert
+    else:
+	sys.exit('Cannot read %s (certificate file)' % opts.cert)
+
+if not all([x for x in (cert, opts.dir, key)]):
+    print >>sys.stderr, "Need output dir, certificate and key to make creds"
+    print >>sys.stderr, "Reverting to debug mode"
+    debug = True
+else:
+    debug = opts.debug
+
+if opts.dir:
+    if opts.make_dir:
+	if not os.path.isdir(opts.dir) and not debug:
+	    try:
+		os.mkdir(opts.dir, 0755)
+	    except EnvironmentError, e:
+		sys.exit('Could not make %s: %s' % (opts.dir, e))
+	if not os.path.isdir(opts.dir):
+	    sys.exit('%s is not a directory' % opts.dir)
+	elif not os.access(opts.dir, os.W_OK):
+	    sys.exit('%s is not writable' % opts.dir)
+
+
+try:
+    roles = parse_configs(args)
+    if not roles:
+	print >>sys.stderr, "No roles found.  Did you specify a configuration?"
+
+    try:
+	credfiles = make_credentials(roles, cert, key, creds_dir, 
+		users, debug)
+    except EnvironmentError, e:
+	sys.exit("Can't create or write %s: %s" % (e.filename, 
+	    e.strerror))
+    except RuntimeError, e:
+	sys.exit('%s' % e)
+
+finally:
+    if delete_certs:
+	if cert: os.unlink(cert)
+	if key: os.unlink(key)
Index: fedd/setup.py
===================================================================
--- fedd/setup.py	(revision 3bcb2eb3beff21eb50bfcd3fb1762dcd9ecdb021)
+++ fedd/setup.py	(revision 45016aef3242f33086944345f268fc1181648aca)
@@ -19,5 +19,5 @@
 	    'fedd_multistatus.py', 'fedd_new.py', 'fedd_ns2topdl.py',
 	    'fedd_spewlog.py', 'fedd_terminate.py', 'fedd_to_abac.py',
-	    'fedid.py', 'user_to_project.py', 'fedd_operation.py', 
-	    'db_to_certs.py', 'deter_exp_access_db.py' ],
+	    'fedd_to_user_certs.py', 'fedid.py', 'user_to_project.py', 
+	    'fedd_operation.py', 'db_to_certs.py', 'deter_exp_access_db.py' ],
     )
