From e278a050ee2db80223200aadc09e38b7f1b8917b Mon Sep 17 00:00:00 2001 From: Narayan Desai Date: Tue, 1 Apr 2008 01:31:19 +0000 Subject: multi-fingerprint support (mainly from Ben Ritcey) git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4464 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Proxy.py | 5 +-- src/sbin/bcfg2 | 97 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/lib/Proxy.py b/src/lib/Proxy.py index 685d2096c..bd0408fbb 100644 --- a/src/lib/Proxy.py +++ b/src/lib/Proxy.py @@ -33,10 +33,7 @@ class RetryMethod(_Method): self.log.error("Server failure: %s" % msg) raise xmlrpclib.Fault(20, msg) except Bcfg2.tlslite.errors.TLSFingerprintError, err: - self.log.error("Server fingerprint did not match") - errmsg = err.message.split() - self.log.error("Got %s expected %s" % (errmsg[3], errmsg[4])) - raise SystemExit, 1 + raise except Bcfg2.tlslite.errors.TLSError, err: self.log.error("Unexpected TLS Error: %s. Retrying" % \ (err.message)) diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index 4912e9d02..83b09e111 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -22,6 +22,8 @@ from Bcfg2.tlslite.errors import TLSNoAuthenticationError, TLSFingerprintError import Bcfg2.Proxy import Bcfg2.Logging +logger = logging.getLogger('bcfg2') + def cb_sigint_handler(signum, frame): '''Exit upon CTRL-C''' os._exit(1) @@ -30,6 +32,55 @@ DECISION_LIST = Bcfg2.Options.Option('Decision List', default=False, cmd="--decision-list", odesc='', long_arg=True) +class FPProxyCall(object): + def __init__(self, proxy, method): + self.proxy = proxy + self.method_name = method + self.method = getattr(self.proxy.proxy, method) + + def __call__(self, *args): + while self.proxy.no_fingerprint or self.proxy.fingerprints: + try: + return self.method(*args) + except Bcfg2.tlslite.errors.TLSFingerprintError: + self.proxy.proxy = self.proxy.get_proxy() + self.method = getattr(self.proxy.proxy, self.method_name) + logger.error("Ran out of valid fingerprints; shutting down") + raise SystemExit(1) + +class FPProxy(object): + def __init__(self, url, user, password, fingerprints): + self.url = url + self.user = user + self.password = password + self.fingerprints = fingerprints + self.no_fingerprint = len(fingerprints) == 0 + self.proxy = self.get_proxy() + + def __getattr__(self, field): + if field not in self.__dict__: + self.__dict__[field] = FPProxyCall(self, field) + return self.__dict__[field] + + def get_proxy(self): + if self.fingerprints: + fprint = self.fingerprints.pop() + elif self.no_fingerprint: + msg = 'no server x509 fingerprint; no server verification performed!' + print >> sys.stderr, msg + fprint = None + else: + print >> sys.stderr, "Ran out of fingerprints to try" + raise SystemExit(1) + + try: + proxy = Bcfg2.Proxy.ComponentProxy(self.url, self.user, + self.password, fprint) + return proxy + except: + logger.error("Unexpected proxy error", exc_info=1) + raise SystemExit(1) + class Client: ''' The main bcfg2 client class ''' @@ -156,15 +207,8 @@ class Client: return(1) else: # retrieve config from server - try: - proxy = Bcfg2.Proxy.ComponentProxy(self.setup['server'], - self.setup['user'], - self.setup['password'], - self.setup['fingerprint']) - except: - self.logger.debug("???", exc_info=1) - self.fatal_error("failed to instantiate proxy to server") - return(1) + proxy = FPProxy(self.setup['server'], self.setup['user'], + self.setup['password'], self.setup['fingerprint']) if self.setup['profile']: try: @@ -256,9 +300,36 @@ class Client: self.logger.error("Failed to upload configuration statistics") raise SystemExit(2) + def GetProxy(self): + '''return a proxy instance, verifying fingerprint(s)''' + prints = self.setup['fingerprint'] + if not prints: + msg = 'no server x509 fingerprint; no server verification performed!' + print >> sys.stderr, msg + + # create the proxy and try to connect - loop for each fingerprint + for p in prints: + try: + proxy = Bcfg2.Proxy.ComponentProxy(self.setup['server'], + self.setup['user'], + self.setup['password'], + p) + proxy.CheckConnection() + return proxy + except Bcfg2.tlslite.errors.TLSFingerprintError: + self.logger.warn("Fingerprint %s failed" % p) + self.logger.warn('Trying next fingerprint, if any') + continue + except: + break + + self.logger.debug("???", exc_info=1) + self.fatal_error("failed to instantiate proxy to server") + raise SystemExit, 1 + class FingerCheck(object): - def __init__(self, fprint): - self.fingerprint = fprint + def __init__(self, fprints): + self.fingerprints = fprints self.logger = logging.getLogger('checker') def __call__(self, connection): @@ -270,12 +341,12 @@ class FingerCheck(object): if chain == None: self.logger.error("Fingerprint authentication error") raise TLSNoAuthenticationError() - if chain.getFingerprint() != self.fingerprint: + if chain.getFingerprint() not in self.fingerprints: self.logger.error("Got connection with bad fingerprint %s" \ % (chain.getFingerprint())) raise TLSFingerprintError(\ "X.509 fingerprint mismatch: %s, %s" % \ - (chain.getFingerprint(), self.fingerprint)) + (chain.getFingerprint(), self.fingerprints)) class Agent(Bcfg2.Component.Component): """The Bcfg2 Agent component providing XML-RPC access to 'run'""" -- cgit v1.2.3-1-g7c22