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