From 3660cf18cca18b0203397c59363f0b2a6d48767f Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 10 Dec 2019 11:54:24 -0500 Subject: [PATCH] Fix a number of issues For one, there were still bytes v. str for python3 issues in the certificate exception and credential handling for smm and generic credential lookup. There was a python2-ism in lldp that needed to be made 2/3 agnostic with ord() of a 'bytes' member, converting to bytearray for normalized behavior. The discovery core had an issue with chained smms where a set was used which cannot take a dict, and so it is converted to a list. If a temporary password is used but the user did not provide a permanent password that is viable, make the error more explicit. --- confluent_server/confluent/discovery/core.py | 8 ++++++-- confluent_server/confluent/discovery/handlers/generic.py | 6 +++++- confluent_server/confluent/discovery/handlers/smm.py | 8 ++++++-- confluent_server/confluent/discovery/handlers/xcc.py | 5 ++++- confluent_server/confluent/exceptions.py | 5 ++++- confluent_server/confluent/networking/lldp.py | 3 ++- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index c8b349f1..4c09622b 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -949,9 +949,9 @@ def eval_node(cfg, handler, info, nodename, manual=False): # raise exc.InvalidArgumentException(errorstr) # log.log({'error': errorstr}) if encuuid in pending_by_uuid: - pending_by_uuid[encuuid].add(info) + pending_by_uuid[encuuid].append(info) else: - pending_by_uuid[encuuid] = set([info]) + pending_by_uuid[encuuid] = [info] return # We found the real smm, replace the list with the actual smm # to continue @@ -1094,6 +1094,10 @@ def discover_node(cfg, handler, info, nodename, manual): info['discostatus'] = 'discovered' for i in pending_by_uuid.get(curruuid, []): eventlet.spawn_n(_recheck_single_unknown_info, cfg, i) + try: + del pending_by_uuid[curruuid] + except KeyError: + pass return True log.log({'info': 'Detected {0}, but discovery.policy is not set to a ' 'value allowing discovery (open or permissive)'.format( diff --git a/confluent_server/confluent/discovery/handlers/generic.py b/confluent_server/confluent/discovery/handlers/generic.py index 6b11e01e..51c52a1e 100644 --- a/confluent_server/confluent/discovery/handlers/generic.py +++ b/confluent_server/confluent/discovery/handlers/generic.py @@ -68,17 +68,21 @@ class NodeHandler(object): def _savecert(self, certificate): self._fp = certificate return True - + def get_node_credentials(self, nodename, creds, defuser, defpass): user = creds.get(nodename, {}).get( 'secret.hardwaremanagementuser', {}).get('value', None) havecustomcreds = False + if user and not isinstance(user, str): + user = user.decode('utf8') if user is not None and user != defuser: havecustomcreds = True else: user = defuser passwd = creds.get(nodename, {}).get( 'secret.hardwaremanagementpassword', {}).get('value', None) + if passwd and not isinstance(passwd, str): + passwd = passwd.decode('utf8') if passwd is not None and passwd != defpass: havecustomcreds = True else: diff --git a/confluent_server/confluent/discovery/handlers/smm.py b/confluent_server/confluent/discovery/handlers/smm.py index cb976cba..8f6564ac 100644 --- a/confluent_server/confluent/discovery/handlers/smm.py +++ b/confluent_server/confluent/discovery/handlers/smm.py @@ -98,7 +98,7 @@ class NodeHandler(bmchandler.NodeHandler): setdata += ',v4Gateway:{0}'.format(gateway) wc.request('POST', '/data', setdata) rsp = wc.getresponse() - rspdata = rsp.read() + rspdata = util.stringify(rsp.read()) if '0' not in rspdata: raise Exception("Error configuring SMM Network") return @@ -145,7 +145,7 @@ class NodeHandler(bmchandler.NodeHandler): authdata['password'] = password wc.request('POST', '/data/login', urlencode(authdata), headers) rsp = wc.getresponse() - rspdata = rsp.read() + rspdata = util.stringify(rsp.read()) if 'authResult>0' in rspdata: tokens = fromstring(rspdata) st2 = tokens.findall('st2')[0].text @@ -181,6 +181,10 @@ class NodeHandler(bmchandler.NodeHandler): 'secret.hardwaremanagementuser', {}).get('value', 'USERID') passwd = creds.get(nodename, {}).get( 'secret.hardwaremanagementpassword', {}).get('value', 'PASSW0RD') + if not isinstance(username, str): + username = username.decode('utf8') + if not isinstance(passwd, str): + passwd = passwd.decode('utf8') if passwd == 'PASSW0RD' and self.ruleset: raise Exception('Cannot support default password and setting password rules at same time') if passwd == 'PASSW0RD': diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index 79678c3b..09f8f8f0 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -208,7 +208,7 @@ class NodeHandler(immhandler.NodeHandler): # however the target *will* demand a new password... if it's currently # PASSW0RD # use TempW0rd42 to avoid divulging a real password on the line - # This is replacing one well known password (PASSW0RD) with another + # This is replacing one well known password (PASSW0RD) with another # (TempW0rd42) passwd = 'TempW0rd42' wc, pwdchanged = self.get_webclient('USERID', 'PASSW0RD', passwd) @@ -363,6 +363,9 @@ class NodeHandler(immhandler.NodeHandler): user, passwd, isdefault = self.get_node_credentials(nodename, creds, 'USERID', 'PASSW0RD') self.set_password_policy(strruleset) if self._atdefaultcreds: + if isdefault and self.tmppasswd: + raise Exception( + 'Request to use default credentials, but refused by target after it has been changed to {0}'.format(self.tmppasswd)) if not isdefault: self._setup_xcc_account(user, passwd, wc) self._convert_sha256account(user, passwd, wc) diff --git a/confluent_server/confluent/exceptions.py b/confluent_server/confluent/exceptions.py index 80f5337e..d9a7f5ab 100644 --- a/confluent_server/confluent/exceptions.py +++ b/confluent_server/confluent/exceptions.py @@ -107,11 +107,14 @@ class PubkeyInvalid(ConfluentException): self.fingerprint = fingerprint self.attrname = attribname self.message = text + certtxt = base64.b64encode(certificate) + if not isinstance(certtxt, str): + certtxt = certtxt.decode('utf8') bodydata = {'message': text, 'event': event, 'fingerprint': fingerprint, 'fingerprintfield': attribname, - 'certificate': base64.b64encode(certificate)} + 'certificate': certtxt} self.errorbody = json.dumps(bodydata) def get_error_body(self): diff --git a/confluent_server/confluent/networking/lldp.py b/confluent_server/confluent/networking/lldp.py index 3b450fb6..dead1da3 100644 --- a/confluent_server/confluent/networking/lldp.py +++ b/confluent_server/confluent/networking/lldp.py @@ -125,7 +125,8 @@ def _dump_neighbordatum(info): def b64tohex(b64str): bd = base64.b64decode(b64str) - return ''.join(['{0:02x}'.format(ord(x)) for x in bd]) + bd = bytearray(bd) + return ''.join(['{0:02x}'.format(x) for x in bd]) def get_fingerprint(switch, port, configmanager, portmatch): update_switch_data(switch, configmanager)