1 | #!/usr/local/bin/python |
---|
2 | |
---|
3 | import re |
---|
4 | import os |
---|
5 | import string |
---|
6 | |
---|
7 | from tempfile import mkstemp |
---|
8 | |
---|
9 | def abac_pem_type(cert): |
---|
10 | key_re = re.compile('\s*-----BEGIN RSA PRIVATE KEY-----$') |
---|
11 | cert_re = re.compile('\s*-----BEGIN CERTIFICATE-----$') |
---|
12 | type = None |
---|
13 | |
---|
14 | f = open(cert, 'r') |
---|
15 | for line in f: |
---|
16 | if key_re.match(line): |
---|
17 | if type is None: type = 'key' |
---|
18 | elif type == 'cert': type = 'both' |
---|
19 | elif cert_re.match(line): |
---|
20 | if type is None: type = 'cert' |
---|
21 | elif type == 'key': type = 'both' |
---|
22 | if type == 'both': break |
---|
23 | f.close() |
---|
24 | return type |
---|
25 | |
---|
26 | def abac_split_cert(cert, keyfile=None, certfile=None): |
---|
27 | """ |
---|
28 | Split the certificate file in cert into a certificate file and a key file |
---|
29 | in cf and kf respectively. The ABAC tools generally cannot handle combined |
---|
30 | certificates/keys. If kf anc cf are given, they are used, otherwise tmp |
---|
31 | files are created. Created tmp files must be deleted. Problems opening or |
---|
32 | writing files will cause exceptions. |
---|
33 | """ |
---|
34 | class diversion: |
---|
35 | ''' |
---|
36 | Wraps up the reqular expression to start and end a diversion, as well as |
---|
37 | the open file that gets the lines. If fd is passed in, use that system |
---|
38 | file (probably from a mkstemp. Otherwise open the given filename. |
---|
39 | ''' |
---|
40 | def __init__(self, start, end, fn=None, fd=None): |
---|
41 | self.start = re.compile(start) |
---|
42 | self.end = re.compile(end) |
---|
43 | |
---|
44 | if not fd: |
---|
45 | # Open the file securely with minimal permissions. NB file |
---|
46 | # cannot exist before this call. |
---|
47 | fd = os.open(fn, |
---|
48 | (os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_EXCL), 0600) |
---|
49 | |
---|
50 | self.f = os.fdopen(fd, 'w') |
---|
51 | |
---|
52 | def close(self): |
---|
53 | self.f.close() |
---|
54 | |
---|
55 | if not keyfile: |
---|
56 | kf, rkeyfile = mkstemp(suffix=".pem") |
---|
57 | else: |
---|
58 | kf, rkeyfile = None, keyfile |
---|
59 | |
---|
60 | if not certfile: |
---|
61 | cf, rcertfile = mkstemp(suffix=".pem") |
---|
62 | else: |
---|
63 | cf, rcertfile = None, certfile |
---|
64 | |
---|
65 | # Initialize the diversions |
---|
66 | divs = [diversion(s, e, fn=pfn, fd=pfd ) for s, e, pfn, pfd in ( |
---|
67 | ('\s*-----BEGIN RSA PRIVATE KEY-----$', |
---|
68 | '\s*-----END RSA PRIVATE KEY-----$', |
---|
69 | keyfile, kf), |
---|
70 | ('\s*-----BEGIN CERTIFICATE-----$', |
---|
71 | '\s*-----END CERTIFICATE-----$', |
---|
72 | certfile, cf))] |
---|
73 | |
---|
74 | # walk through the file, beginning a diversion when a start regexp |
---|
75 | # matches until the end regexp matches. While in the two regexps, |
---|
76 | # print each line to the open diversion file (including the two |
---|
77 | # matches). |
---|
78 | active = None |
---|
79 | f = open(cert, 'r') |
---|
80 | for l in f: |
---|
81 | if active: |
---|
82 | if active.end.match(l): |
---|
83 | print >>active.f, l, |
---|
84 | active = None |
---|
85 | else: |
---|
86 | for d in divs: |
---|
87 | if d.start.match(l): |
---|
88 | active = d |
---|
89 | break |
---|
90 | if active: print >>active.f, l, |
---|
91 | |
---|
92 | # This is probably unnecessary. Close all the diversion files. |
---|
93 | for d in divs: d.close() |
---|
94 | return rkeyfile, rcertfile |
---|
95 | |
---|
96 | def abac_context_to_creds(context): |
---|
97 | """ |
---|
98 | Pull all the credentials out of the context and return 2 lists of the |
---|
99 | underlying credentials in an exportable format, IDs and attributes. |
---|
100 | There are no duplicates in the lists. |
---|
101 | """ |
---|
102 | ids, attrs = set(), set() |
---|
103 | # This should be a one-iteration loop |
---|
104 | for c in context.credentials(): |
---|
105 | ids.add(str(c.issuer_cert())) |
---|
106 | attrs.add(str(c.attribute_cert())) |
---|
107 | |
---|
108 | return list(ids), list(attrs) |
---|
109 | |
---|
110 | |
---|
111 | |
---|
112 | def remove_dirs(dname): |
---|
113 | """ |
---|
114 | Remove the directory tree and all files rooted at dir. Log any errors, |
---|
115 | but continue. |
---|
116 | """ |
---|
117 | for path, dirs, files in os.walk(dname, topdown=False): |
---|
118 | for f in files: |
---|
119 | os.remove(os.path.join(path, f)) |
---|
120 | for d in dirs: |
---|
121 | os.rmdir(os.path.join(path, d)) |
---|
122 | os.rmdir(dname) |
---|
123 | |
---|