[87c0fc1] | 1 | #!/usr/local/bin/python |
---|
| 2 | |
---|
| 3 | import sys |
---|
| 4 | import re |
---|
| 5 | |
---|
| 6 | import os |
---|
| 7 | import os.path |
---|
| 8 | import subprocess |
---|
| 9 | |
---|
| 10 | from string import join |
---|
| 11 | from optparse import OptionParser |
---|
| 12 | |
---|
[c573278] | 13 | from federation.util import abac_pem_type, abac_split_cert |
---|
| 14 | |
---|
[87c0fc1] | 15 | class Parser(OptionParser): |
---|
| 16 | def __init__(self): |
---|
| 17 | OptionParser.__init__(self) |
---|
| 18 | self.add_option('--cert', dest='cert', default=None, |
---|
| 19 | help='my fedid as an X.509 certificate') |
---|
| 20 | self.add_option('--key', dest='key', default=None, |
---|
| 21 | help='key for the certificate') |
---|
| 22 | self.add_option('--dir', dest='dir', default=None, |
---|
| 23 | help='Output directory for credentials') |
---|
| 24 | self.add_option('--make-dir', action='store_true', dest='make_dir', |
---|
| 25 | default=False, help='Create the --dir directory') |
---|
| 26 | self.add_option('--debug', action='store_true', dest='debug', |
---|
| 27 | default=False, help='Just print the creddy commands') |
---|
| 28 | |
---|
| 29 | class identity: |
---|
| 30 | def __init__(self, name, roles=None): |
---|
| 31 | self.name = name |
---|
| 32 | if roles: self.roles = set(roles) |
---|
| 33 | |
---|
| 34 | def add_roles(self, roles): |
---|
| 35 | self.roles |= set(roles) |
---|
| 36 | |
---|
| 37 | def __str__(self): |
---|
| 38 | return "%s: %s" % (self.name, join(self.roles, ', ')) |
---|
| 39 | |
---|
| 40 | comment_re = re.compile('^\s*#|^$') |
---|
| 41 | fedid_str = 'fedid:([0-9a-fA-F]{40})' |
---|
| 42 | id_str = '[a-zA-Z][\w_-]*' |
---|
| 43 | single_re = re.compile('\s*%s\s*->\s*(%s)' % (fedid_str, id_str)) |
---|
| 44 | double_re = re.compile('\s*%s\s*->\s*\((%s)\s*,\s*(%s)\)' % \ |
---|
| 45 | (fedid_str, id_str, id_str)) |
---|
[aba14f4] | 46 | bad_role = re.compile('[^a-zA-Z0-9_]+') |
---|
[87c0fc1] | 47 | |
---|
| 48 | parser = Parser() |
---|
| 49 | opts, args = parser.parse_args() |
---|
[c573278] | 50 | cert, key = None, None |
---|
| 51 | delete_certs = False |
---|
[87c0fc1] | 52 | |
---|
| 53 | |
---|
| 54 | |
---|
[c573278] | 55 | if opts.key: |
---|
| 56 | if os.access(opts.key, os.R_OK): key = opts.key |
---|
| 57 | else: sys.exit('Cannot read %s (key file)' % opts.key) |
---|
[87c0fc1] | 58 | |
---|
| 59 | if opts.dir: |
---|
| 60 | if opts.make_dir: |
---|
| 61 | if not os.path.isdir(opts.dir) and not debug: |
---|
| 62 | try: |
---|
| 63 | os.mkdir(opts.dir, 0755) |
---|
| 64 | except EnvironmentError, e: |
---|
| 65 | sys.exit('Could not make %s: %s' % (opts.dir, e)) |
---|
| 66 | else: |
---|
| 67 | if not os.path.isdir(opts.dir): |
---|
| 68 | sys.exit('%s is not a directory' % opts.dir) |
---|
| 69 | elif not os.access(opts.dir, os.W_OK): |
---|
| 70 | sys.exit('%s is not writable' % opts.dir) |
---|
| 71 | |
---|
[c573278] | 72 | if opts.cert: |
---|
| 73 | if os.access(opts.cert, os.R_OK): |
---|
| 74 | if not key: |
---|
| 75 | if abac_pem_type(opts.cert) == 'both': |
---|
| 76 | key, cert = abac_split_cert(opts.cert) |
---|
| 77 | delete_certs = True |
---|
| 78 | else: |
---|
| 79 | cert = opts.cert |
---|
| 80 | else: |
---|
| 81 | sys.exit('Cannot read %s (certificate file)' % opts.cert) |
---|
[87c0fc1] | 82 | |
---|
[c573278] | 83 | if any([ x is None for x in (cert, opts.dir, key)]): |
---|
| 84 | print >>sys.stderr, "Need output dir, certificate and key to make creds" |
---|
| 85 | print >>sys.stderr, "Reverting to debug mode" |
---|
| 86 | debug = True |
---|
| 87 | else: |
---|
| 88 | debug = opts.debug |
---|
[87c0fc1] | 89 | |
---|
[c573278] | 90 | roles = { } |
---|
| 91 | try: |
---|
| 92 | for fn in args: |
---|
| 93 | try: |
---|
| 94 | f = open(fn, "r") |
---|
| 95 | for l in f: |
---|
| 96 | id = None |
---|
| 97 | for r in (comment_re, single_re, double_re): |
---|
| 98 | m = r.match(l) |
---|
| 99 | if m: |
---|
| 100 | if m.groups(): |
---|
| 101 | g = m.groups() |
---|
| 102 | id = g[0] |
---|
| 103 | r = [ bad_role.sub('_', x) for x in g[1:] ] |
---|
| 104 | break |
---|
| 105 | else: |
---|
| 106 | print 'Unmatched line: %s' % l |
---|
| 107 | if id: |
---|
| 108 | # New and create are implicit. >sigh< |
---|
| 109 | r.extend(('new', 'create')) |
---|
| 110 | if id in roles: roles[id].add_roles(r) |
---|
| 111 | else: roles[id] = identity(r[0], r) |
---|
| 112 | |
---|
| 113 | except EnvironmentError, e: |
---|
| 114 | print >>sys.stderr, 'Cannot open file (%s): %s' % \ |
---|
| 115 | (e.filename, e.strerror) |
---|
| 116 | |
---|
| 117 | if not roles: |
---|
| 118 | print >>sys.stderr, "No roles found. Did you specify a configuration?" |
---|
| 119 | |
---|
| 120 | for k, id in roles.items(): |
---|
| 121 | for i, r in enumerate(id.roles): |
---|
| 122 | cmd = ['creddy', '--attribute', |
---|
| 123 | '--issuer=%s' % (cert or 'cert_file'), |
---|
| 124 | '--key=%s' % (key or 'key_file'), '--role=%s' % r, |
---|
| 125 | '--subject-id=%s' % k, |
---|
| 126 | '--out=%s/%s%03d_attr.der' % \ |
---|
| 127 | (opts.dir or 'new_cert_dir', id.name, i)] |
---|
| 128 | if debug: |
---|
| 129 | print join(cmd) |
---|
[87c0fc1] | 130 | else: |
---|
[c573278] | 131 | rv = subprocess.call(cmd) |
---|
| 132 | if rv != 0: |
---|
| 133 | sys.exit('%s failed: %d' % (join(cmd), rv)) |
---|
| 134 | finally: |
---|
| 135 | if delete_certs: |
---|
| 136 | if cert: os.unlink(cert) |
---|
| 137 | if key: os.unlink(key) |
---|