implement verbose output, fix name errors
[sfa.git] / sfa / server / sfa-ca.py
1 #!/usr/bin/python
2
3 #
4 # SFA Certificate Signing and management 
5 #   
6
7 import os
8 import sys
9 from optparse import OptionParser
10 from sfa.trust.certificate import Keypair, Certificate
11 from sfa.trust.gid import GID, create_uuid
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.util.config import Config
14 from collections import defaultdict
15
16 def main():
17     args = sys.argv
18     script_name = args[0]
19     parser = OptionParser(usage="%(script_name)s [options]" % locals())
20     parser.add_option("-d", "--display", dest="display", default=None,
21                       help="print contents of specified gid")           
22     parser.add_option("-s", "--sign", dest="sign", default=None, 
23                       help="gid to sign" )
24     parser.add_option("-k", "--key", dest="key", default=None, 
25                       help="keyfile to use for signing")
26     parser.add_option("-a", "--authority", dest="authority", default=None, 
27                       help="sign the gid using the specified authority ")
28     parser.add_option("-i", "--import", dest="importgid", default=None,
29                       help="gid file to import into the registry")
30     parser.add_option("-e", "--export", dest="export", 
31                       help="name of gid to export from registry")
32     parser.add_option("-o", "--outfile", dest="outfile",
33                       help="where to write the exprted gid") 
34     parser.add_option("-v", "--verbose", dest="verbose", default=False, 
35                       action="store_true", help="be verbose")           
36                 
37     (options, args) = parser.parse_args()
38
39
40     if options.display:
41         display(options)
42     elif options.sign:
43         sign(options)
44     elif options.importgid:
45         import_gid(options) 
46     elif options.export:
47         export_gid(options)  
48     else:
49         parser.print_help()
50         sys.exit(1)        
51
52
53 def display(options):
54     """
55     Display the sepcified GID
56     """
57     gidfile = os.path.abspath(options.display)
58     if not gidfile or not os.path.isfile(gidfile):
59         print "No such gid: %s" % gidfile
60         sys.exit(1)
61     gid = GID(filename=gidfile)
62     gid.dump(dump_parents=True)
63
64 def sign_gid(gid, parent_key, parent_gid):
65     gid.set_issuer(parent_key, parent_gid.get_hrn())
66     gid.set_parent(parent_gid)
67     gid.sign()
68     return gid 
69
70 def sign(options):
71     """
72     Sign the specified gid
73     """
74     hierarchy = Hierarchy()
75     config = Config()
76     default_authority = config.SFA_INTERFACE_HRN
77     auth_info = hierarchy.get_auth_info(default_authority)
78
79     # load the gid
80     gidfile = os.path.abspath(options.sign)
81     if not os.path.isfile(gidfile):
82         print "no such gid: %s" % gidfile
83         sys.exit(1)
84     gid = GID(filename=gidfile)
85
86     # remove previous parent
87     gid = GID(string=gid.save_to_string(save_parents=False))
88
89     # load the parent private info
90     authority = options.authority    
91     # if no pkey was specified, then use the this authority's key
92     if not authority:
93         authority = default_authority 
94     
95     if not hierarchy.auth_exists(authority):
96         print "no such authority: %s" % authority    
97
98     # load the parent gid and key 
99     auth_info = hierarchy.get_auth_info(authority)
100     pkeyfile = auth_info.privkey_filename
101     parent_key = Keypair(filename=pkeyfile)
102     parent_gid = auth_info.gid_object
103
104     # get the outfile
105     outfile = options.outfile
106     if not outfile:
107         outfile = os.path.abspath('./signed-%s.gid' % gid.get_hrn())
108    
109     # check if gid already has a parent
110  
111     # sign the gid
112     if options.verbose:
113         print "Signing %s gid with parent %s" % \
114               (gid.get_hrn(), parent_gid.get_hrn())
115     gid = sign_gid(gid, parent_key, parent_gid)
116     # save the signed gid
117     if options.verbose:
118         print "Writing signed gid %s" % outfile  
119     gid.save_to_file(outfile, save_parents=True)
120     
121
122 def export_gid(options):
123     from sfa.util.table import SfaTable
124     # lookup the record for the specified hrn 
125     hrn = options.export
126
127     # check sfa table first    
128     table = SfaTable()
129     records = table.find({'hrn': hrn, type: 'authority'})
130     if not records:
131         # check the authorities hierarchy 
132         hierarchy = Hierarchy()
133         try:
134             auth_info = hierarchy.get_auth_info()
135             gid = auth_info.gid_object 
136         except:
137             print "Record: %s not found" % hrn
138             sys.exit(1)
139     else:
140         record = records[0]
141         gid = GID(string=record['gid'])
142         
143     # get the outfile
144     outfile = options.outfile
145     if not outfile:
146         outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
147
148     # save it
149     if options.verbose:
150         print "Writing %s gid to %s" % (gid.get_hrn(), outfile)
151     gid.save_to_file(outfile, save_parents=True)
152
153 def import_gid(options):
154     """
155     Import the specified gid into the registry (db and authorities 
156     hierarchy) overwriting any previous gid.
157     """
158     from sfa.util.table import SfaTable
159     from sfa.util.record import SfaRecord
160     # load the gid
161     gidfile = os.path.abspath(options.importgid)
162     if not gidfile or not os.path.isfile(gidfile):
163         print "No such gid: %s" % gidfile
164         sys.exit(1)
165     gid = GID(filename=gidfile)
166     
167     # check if it exists within the hierarchy
168     hierarchy = Hierarchy()
169     if not hierarchy.auth_exists(gid.get_hrn()):
170         print "%s not found in hierarchy" % gid.get_hrn()
171         sys.exit(1)
172
173     # check if record exists in db
174     table = SfaTable()
175     records = table.find({'hrn': gid.get_hrn(), 'type': 'authority'})
176     if not records:
177         print "%s not found in record database" % get.get_hrn()  
178         sys.exit(1)
179
180     # update the database record
181     record = records[0]
182     record['gid'] = gid.save_to_string(save_parents=True)
183     table.update(record)
184     if options.verbose:
185         print "Imported %s gid into db" % record['hrn']
186
187     # update the hierarchy
188     auth_info = hierarchy.get_auth_info(gid.get_hrn())  
189     filename = auth_info.gid_filename
190     gid.save_to_file(filename, save_parents=True)
191     if options.verbose:
192         print "Writing %s gid to %s" % (gid.get_hrn(), filename)
193
194     # re-sign all existing gids signed by this authority  
195     # create a dictionary of records keyed on the record's authority
196     record_dict = defaultdict(list)
197     # only get regords that belong to this authority 
198     # or any of its sub authorities   
199     child_records = table.find({'hrn': '%s*' % gid.get_hrn()})
200     if not child_records:
201         return
202   
203     for record in child_records:
204         record_dict[record['authority']].append(record) 
205
206     # start with the authority we just imported       
207     authorities = [gid.get_hrn()]
208     while authorities:
209         next_authorities = []
210         for authority in authorities:
211             # create a new signed gid for each record at this authority 
212             # and update the registry
213             auth_info = hierarchy.get_auth_info(authority)
214             records = record_dict[authority]
215             for record in records:
216                 record_gid = GID(string=record['gid'])
217                 parent_pkey = Keypair(filename=auth_info.privkey_filename)
218                 parent_gid = GID(filename=auth_info.gid_filename)
219                 if options.verbose:
220                     print "re-signing %s gid with parent %s" % \
221                            (record['hrn'], parent_gid.get_hrn())  
222                 signed_gid = sign_gid(record_gid, parent_pkey, parent_gid)
223                 record['gid'] = signed_gid.save_to_string(save_parents=True)
224                 table.update(record)
225                 
226                 # if this is an authority then update the hierarchy
227                 if record['type'] == 'authority':
228                     record_info = hierarchy.get_auth_info(record['hrn'])
229                     if options.verbose:
230                         print "Writing %s gid to %s" % (record['hrn'], record_info.gid_filename) 
231                     signed_gid.save_to_file(filename=record_info.gid_filename, save_parents=True)
232
233              # update list of next authorities
234             tmp_authorities = set([record['hrn'] for record in records \
235                                    if record['type'] == 'authority'])
236             next_authorities.extend(tmp_authorities)
237
238         # move on to next set of authorities
239         authorities = next_authorities     
240
241 if __name__ == '__main__':
242     main()