reset gids passing urn to get the correct type
[sfa.git] / sfa / client / sfaresetgids.py
1 #!/usr/bin/python
2
3 from __future__ import print_function
4
5 from argparse import ArgumentParser
6
7 from sfa.util.config import Config
8 from sfa.storage.alchemy import alchemy
9 from sfa.storage.model import RegRecord
10 from sfa.trust.hierarchy import Hierarchy
11 from sfa.trust.certificate import convert_public_key, Keypair
12 from sfa.util.xrn import hrn_to_urn
13
14 """
15 WARNING : This script is not exactly thoroughly tested
16
17 BEFORE YOU USE
18 * backup the sfa db
19 * backup the /var/lib/sfa/authorities tree
20 * make sure to keep all this for a while 
21   in case for example the old uuids turn out to be needed
22
23 PURPOSE
24
25 Regenerates gids; mostly useful when your root gid is old or obsolete
26 for any other reason (like, it's still md5 signed)
27
28 POLICIES
29
30 all  : regenerate everything no matter what, including toplevel gid
31 safe : regenerate everything *except* toplevel 
32 incremental : was useful during development mostly; 
33
34 WHAT IT DOES
35
36 authorities : a new gid is issued
37 users : a new gid is created with email, pubkey, and uuid restored from the previous ones
38
39 HOW TO USE
40
41 . do the backups - see above
42 . shutdown your sfa service
43 . rm -rf /var/lib/sfa/authorities
44 . run the script (run directly with python, no entry point is installed in PATH)
45 . restart the service
46
47 . on the client side, trash any old sscert or gids or similar
48
49 """
50
51
52 class SfaResetGids:
53     def __init__(self, session, tophrn):
54         self.session = session
55         self.tophrn = tophrn
56
57     def load_local_records(self):
58         """
59         read the database for records that start with tophrn.*
60         and sort them by hrn
61         """
62         # just making sure we don't mess with anything else
63         # than our own local business
64         self.records = self.session.query(RegRecord)\
65                        .filter(RegRecord.hrn.op('~')("{}.*".format(self.tophrn)))\
66                        .order_by(RegRecord.hrn)
67
68     def regenerate(self, policy='safe'):
69         """
70         For all local records, gid gets regenerated
71         policy parameter works as follows
72         * all :
73           all gids get renewed, including toplevel hrn, no matter what
74         * safe : 
75           gid for toplevel hrn gets regenerated only if not yet existing
76           in SFA_DATA_DIR (i.e. /var/lib/sfa/authorities/<hrn>/hrn.{gid,key})
77           all others are redone
78         * incremental :
79           recreate only for entities not present in SFA_DATA_DIR
80         """
81
82         count_auths, count_users, count_slices = 0, 0, 0
83         hierarchy = Hierarchy()
84         for record in self.records:
85             print(record.hrn)
86             ########## not an autority nor a user nor a slice: ignored
87             # Just wondering what other type it could be...
88             if record.type not in ['authority', 'user', 'slice']:
89                 message = ''
90                 if record.gid:
91                     message = '[GID cleared]'
92                     record.gid = None
93                 print("SKP (non-auth) {} {} : {}"
94                       .format(message, record.type, record.hrn))
95                 continue
96             ########## toplevel : be careful 
97             if record.hrn == self.tophrn:
98                 if policy != 'all':
99                     print("SKP (toplevel) - type={} - policy={}"
100                           .format(record.type, policy))
101                     continue
102             ########## user : rebuild a gid from pubkey and email
103             if record.type == 'user':
104                 hrn = str(record.hrn)
105                 urn = hrn_to_urn(hrn, str(record.type))
106                 gid = record.get_gid_object()
107                 uuid = gid.get_uuid()
108                 pub = gid.get_pubkey()
109                 email = gid.get_email()
110                 print("pub {} uuid {}... email {}".format(pub, str(uuid)[:6], email))
111                 new_gid = hierarchy.create_gid(urn, uuid, pub, email=email)
112                 new_gid_str = new_gid.save_to_string()
113                 record.gid = new_gid_str
114                 print("NEW {} {} [{}]".format(record.type, record.hrn, email))
115                 count_users += 1
116                 continue
117             ########## authorities
118             if record.type == 'authority':
119                 if policy in ('all', 'safe'):
120                     redo = True
121                 else:
122                     redo = not hierarchy.auth_exists(record.hrn)
123                 if not redo:
124                     print("IGN (existing) {}".format(record.hrn))
125                 else:
126                     print("NEW {} {}".format(record.type, record.hrn))
127                     # because we have it sorted we should not need create_parents
128                     gid = hierarchy.create_auth(str(record.hrn))
129                     record.gid = gid
130                     count_auths += 1
131             ########## slices
132             if record.type == 'slice':
133                 hrn = str(record.hrn)
134                 urn = hrn_to_urn(hrn, str(record.type))
135                 gid = record.get_gid_object()
136                 uuid = gid.get_uuid()
137                 pub = gid.get_pubkey()
138                 print("pub {} uuid {}...".format(pub, str(uuid)[:6]))
139                 new_gid = hierarchy.create_gid(urn, uuid, pub)
140                 new_gid_str = new_gid.save_to_string()
141                 record.gid = new_gid_str
142                 print("NEW {} {}".format(record.type, record.hrn))
143                 count_slices += 1
144                 continue
145         #
146         print("Committing to the DB {} new auth gids and {} new user gids and {} new slice gids"
147               .format(count_auths, count_users, count_slices))
148         self.session.commit()
149         return True
150
151     def main(self):
152         parser = ArgumentParser()
153         parser.add_argument("--policy", choices=('all', 'safe', 'incremental'),
154                             default='safe')
155         args = parser.parse_args()
156
157         self.load_local_records()
158         return 0 if self.regenerate(args.policy) else 1
159
160 ###
161 if __name__ == '__main__':
162     session = alchemy.session()
163     tophrn = Config().SFA_REGISTRY_ROOT_AUTH
164     SfaResetGids(session, tophrn).main()