From a4d98464dd61e26c7503d498c68a0cd1219b12bb Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Thu, 9 Feb 2017 16:25:00 +0100 Subject: [PATCH] sfaresetgids is a script that can refresh gids esp. useful when toplevel cert needs to be issued again requires the sfa service to be stopped --- sfa/client/sfaresetgids.py | 142 +++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 sfa/client/sfaresetgids.py diff --git a/sfa/client/sfaresetgids.py b/sfa/client/sfaresetgids.py new file mode 100644 index 00000000..c4936017 --- /dev/null +++ b/sfa/client/sfaresetgids.py @@ -0,0 +1,142 @@ +from __future__ import print_function + +from argparse import ArgumentParser + +from sfa.util.config import Config +from sfa.storage.alchemy import alchemy +from sfa.storage.model import RegRecord +from sfa.trust.hierarchy import Hierarchy + +""" +WARNING : This script is not exactly thoroughly tested + +BEFORE YOU USE +* backup the sfa db +* backup the /var/lib/sfa/authorities tree +* make sure to keep all this for a while + in case for example the old uuids turn out to be needed + +PURPOSE + +Regenerates gids; mostly useful when your root gid is old or obsolete +for any other reason (like, it's still md5 signed) + +POLICIES + +all : regenerate everything no matter what, including toplevel gid +safe : regenerate everything *except* toplevel +incremental : was useful during development mostly; + +WHAT IT DOES + +authorities : a new gid is issued +users : a new gid is created with email, pubkey, and uuid restored from the previous ones + +HOW TO USE + +. do the backups - see above +. shutdown your sfa service +. rm -rf /var/lib/sfa/authorities +. run the script (run directly with python, no entry point is installed in PATH) +. restart the service + +. on the client side, trash any old sscert or gids or similar + +""" + + +class SfaResetGids: + def __init__(self, session, tophrn): + self.session = session + self.tophrn = tophrn + + def load_local_records(self): + """ + read the database for records that start with tophrn.* + and sort them by hrn + """ + # just making sure we don't mess with anything else + # than our own local business + self.records = self.session.query(RegRecord)\ + .filter(RegRecord.hrn.op('~')("{}.*".format(self.tophrn)))\ + .order_by(RegRecord.hrn) + + def regenerate(self, policy='safe'): + """ + For all local records, gid gets regenerated + policy parameter works as follows + * all : + all gids get renewed, including toplevel hrn, no matter what + * safe : + gid for toplevel hrn gets regenerated only if not yet existing + in SFA_DATA_DIR (i.e. /var/lib/sfa/authorities//hrn.{gid,key}) + all others are redone + * incremental : + recreate only for entities not present in SFA_DATA_DIR + """ + + count_auths, count_users = 0, 0 + hierarchy = Hierarchy() + for record in self.records: + ########## not an autority nor a user : ignored + if 'authority' not in record.type and 'user' not in record.type: + message = '' + if record.gid: + message = '[GID cleared]' + record.gid = None + print("SKP (non-auth) {} {} : {}" + .format(message, record.type, record.hrn)) + continue + ########## toplevel : be careful + if record.hrn == self.tophrn: + if policy != 'all': + print("SKP (toplevel) - type={} - policy={}" + .format(record.type, policy)) + continue + ########## user : rebuild a gid from pubkey and email + if record.type == 'user': + hrn = str(record.hrn) + gid = record.get_gid_object() + uuid = gid.get_uuid() + pub = gid.get_pubkey() + email = gid.get_email() + print("pub {} uuid {}... email {}".format(pub, str(uuid)[:6], email)) + new_gid = hierarchy.create_gid(hrn, uuid, pub, email=email) + new_gid_str = new_gid.save_to_string() + record.gid = new_gid_str + print("NEW {} {} [{}]".format(record.type, record.hrn, email)) + count_users += 1 + continue + ########## authorities + if policy in ('all', 'safe'): + redo = True + else: + redo = not hierarchy.auth_exists(record.hrn) + if not redo: + print("IGN (existing) {}".format(record.hrn)) + else: + print("NEW {} {}".format(record.type, record.hrn)) + # because we have it sorted we should not need create_parents + gid = hierarchy.create_auth(str(record.hrn)) + record.gid = gid + count_auths += 1 + # + print("Committing to the DB {} new auth gids and {} new user gids" + .format(count_auths, count_users)) + self.session.commit() + return True + + def main(self): + parser = ArgumentParser() + parser.add_argument("--policy", choices=('all', 'safe', 'incremental'), + default='safe') + args = parser.parse_args() + + self.load_local_records() + return 0 if self.regenerate(args.policy) else 1 + +### +if __name__ == '__main__': + session = alchemy.session() + tophrn = Config().SFA_REGISTRY_ROOT_AUTH + SfaResetGids(session, tophrn).main() -- 2.43.0