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