a2266c658f402a15f6670f46b17849847fb17e49
[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     # load the parent private info
87     authority = options.authority    
88     # if no pkey was specified, then use the this authority's key
89     if not authority:
90         authority = default_authority 
91     
92     if not hierarchy.auth_exists(authority):
93         print "no such authority: %s" % authority    
94
95     # load the parent gid and key 
96     auth_info = hierarchy.get_auth_info(authority)
97     pkeyfile = auth_info.privkey_filename
98     parent_key = Keypair(filename=pkeyfile)
99     parent_gid = auth_info.gid_object
100
101     # get the outfile
102     outfile = options.outfile
103     if not outfile:
104         outfile = os.path.abspath('./signed-%s.gid' % gid.get_hrn())
105    
106     # check if gid already has a parent
107  
108     # sign the gid
109     if options.verbose:
110         print "Signing %s gid with parent %s" % \
111               (gid.get_hrn(), parent_gid.get_hrn())
112     gid = sign_gid(gid, parent_key, parent_gid)
113     # save the signed gid
114     if options.verbose:
115         print "Writing signed gid %s" % outfile  
116     gid.save_to_file(outfile, save_parents=True)
117     
118
119 def export_gid(options):
120     from sfa.util.table import SfaTable
121     # lookup the record for the specified hrn 
122     hrn = options.export
123
124     # check sfa table first    
125     table = SfaTable()
126     records = table.find({'hrn': hrn, type: 'authority'})
127     if not records:
128         # check the authorities hierarchy 
129         hierarchy = Hierarchy()
130         try:
131             auth_info = hierarchy.get_auth_info()
132             gid = auth_info.gid_object 
133         except:
134             print "Record: %s not found" % hrn
135             sys.exit(1)
136     else:
137         record = records[0]
138         gid = GID(string=record['gid'])
139         
140     # get the outfile
141     outfile = options.outfile
142     if not outfile:
143         outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
144
145     # save it
146     if options.verbose:
147         print "Writing %s gid to %s" % (gid.get_hrn(), outfile)
148     gid.save_to_file(outfile, save_parents=True)
149
150 def import_gid(options):
151     """
152     Import the specified gid into the registry (db and authorities 
153     hierarchy) overwriting any previous gid.
154     """
155     from sfa.util.table import SfaTable
156     from sfa.util.record import SfaRecord
157     # load the gid
158     gidfile = os.path.abspath(options.importgid)
159     if not gidfile or not os.path.isfile(gidfile):
160         print "No such gid: %s" % gidfile
161         sys.exit(1)
162     gid = GID(filename=gidfile)
163     
164     # check if it exists within the hierarchy
165     hierarchy = Hierarchy()
166     if not hierarchy.auth_exists(gid.get_hrn()):
167         print "%s not found in hierarchy" % gid.get_hrn()
168         sys.exit(1)
169
170     # check if record exists in db
171     table = SfaTable()
172     records = table.find({'hrn': gid.get_hrn(), 'type': 'authority'})
173     if not records:
174         print "%s not found in record database" % get.get_hrn()  
175         sys.exit(1)
176
177     # update the database record
178     record = records[0]
179     record['gid'] = gid.save_to_string(save_parents=True)
180     table.update(record)
181     if options.verbose:
182         print "Imported %s gid into db" % record['hrn']
183
184     # update the hierarchy
185     auth_info = hierarchy.get_auth_info(gid.get_hrn())  
186     filename = auth_info.gid_filename
187     gid.save_to_file(filename, save_parents=True)
188     if options.verbose:
189         print "Writing %s gid to %s" % (gid.get_hrn(), filename)
190
191     # re-sign all existing gids signed by this authority  
192     # create a dictionary of records keyed on the record's authority
193     record_dict = defaultdict(list)
194     # only get regords that belong to this authority 
195     # or any of its sub authorities   
196     child_records = table.find({'hrn': '%s*' % gid.get_hrn()})
197     if not child_records:
198         return
199   
200     for record in child_records:
201         record_dict[record['authority']].append(record) 
202
203     # start with the authority we just imported       
204     authorities = [gid.get_hrn()]
205     while authorities:
206         next_authorities = []
207         for authority in authorities:
208             # create a new signed gid for each record at this authority 
209             # and update the registry
210             auth_info = hierarchy.get_auth_info(authority)
211             records = record_dict[authority]
212             for record in records:
213                 record_gid = GID(string=record['gid'])
214                 parent_pkey = Keypair(filename=auth_info.privkey_filename)
215                 parent_gid = GID(filename=auth_info.gid_filename)
216                 if options.verbose:
217                     print "re-signing %s gid with parent %s" % \
218                            (record['hrn'], parent_gid.get_hrn())  
219                 signed_gid = sign_gid(record_gid, parent_pkey, parent_gid)
220                 record['gid'] = signed_gid.save_to_string(save_parents=True)
221                 table.update(record)
222                 
223                 # if this is an authority then update the hierarchy
224                 if record['type'] == 'authority':
225                     record_info = hierarchy.get_auth_info(record['hrn'])
226                     if options.verbose:
227                         print "Writing %s gid to %s" % (record['hrn'], record_info.gid_filename) 
228                     signed_gid.save_to_file(filename=record_info.gid_filename, save_parents=True)
229
230              # update list of next authorities
231             tmp_authorities = set([record['hrn'] for record in records \
232                                    if record['type'] == 'authority'])
233             next_authorities.extend(tmp_authorities)
234
235         # move on to next set of authorities
236         authorities = next_authorities     
237
238 if __name__ == '__main__':
239     main()