Sync latest process and str utils from oslo
This sync required changes to fix these issues: * Make execute method clean password in exception * Make sure mask_password works properly ------------------------------------------------ The sync pulls in the following changes (newest to oldest): 6a60f842 - Mask passwords in exceptions and error messages (SSH) 63c99a0f - Mask passwords in exceptions and error messages 66142c34 - Make strutils.mask_password more secure ----------------------------------------------- Closes-Bug: 1343604 Closes-Bug: 1345233 SecurityImpact Change-Id: I3b49b1d667f6ade9ae3f6765d735440a3e838917
This commit is contained in:
parent
e24bd6ba1b
commit
9672744f09
|
@ -150,12 +150,12 @@ def execute(*cmd, **kwargs):
|
||||||
cmd = shlex.split(root_helper) + list(cmd)
|
cmd = shlex.split(root_helper) + list(cmd)
|
||||||
|
|
||||||
cmd = map(str, cmd)
|
cmd = map(str, cmd)
|
||||||
|
sanitized_cmd = strutils.mask_password(' '.join(cmd))
|
||||||
|
|
||||||
while attempts > 0:
|
while attempts > 0:
|
||||||
attempts -= 1
|
attempts -= 1
|
||||||
try:
|
try:
|
||||||
LOG.log(loglevel, 'Running cmd (subprocess): %s',
|
LOG.log(loglevel, _('Running cmd (subprocess): %s'), sanitized_cmd)
|
||||||
strutils.mask_password(' '.join(cmd)))
|
|
||||||
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
@ -192,16 +192,18 @@ def execute(*cmd, **kwargs):
|
||||||
LOG.log(loglevel, 'Result was %s' % _returncode)
|
LOG.log(loglevel, 'Result was %s' % _returncode)
|
||||||
if not ignore_exit_code and _returncode not in check_exit_code:
|
if not ignore_exit_code and _returncode not in check_exit_code:
|
||||||
(stdout, stderr) = result
|
(stdout, stderr) = result
|
||||||
|
sanitized_stdout = strutils.mask_password(stdout)
|
||||||
|
sanitized_stderr = strutils.mask_password(stderr)
|
||||||
raise ProcessExecutionError(exit_code=_returncode,
|
raise ProcessExecutionError(exit_code=_returncode,
|
||||||
stdout=stdout,
|
stdout=sanitized_stdout,
|
||||||
stderr=stderr,
|
stderr=sanitized_stderr,
|
||||||
cmd=' '.join(cmd))
|
cmd=sanitized_cmd)
|
||||||
return result
|
return result
|
||||||
except ProcessExecutionError:
|
except ProcessExecutionError:
|
||||||
if not attempts:
|
if not attempts:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
LOG.log(loglevel, '%r failed. Retrying.', cmd)
|
LOG.log(loglevel, _('%r failed. Retrying.'), sanitized_cmd)
|
||||||
if delay_on_retry:
|
if delay_on_retry:
|
||||||
greenthread.sleep(random.randint(20, 200) / 100.0)
|
greenthread.sleep(random.randint(20, 200) / 100.0)
|
||||||
finally:
|
finally:
|
||||||
|
@ -240,7 +242,8 @@ def trycmd(*args, **kwargs):
|
||||||
|
|
||||||
def ssh_execute(ssh, cmd, process_input=None,
|
def ssh_execute(ssh, cmd, process_input=None,
|
||||||
addl_env=None, check_exit_code=True):
|
addl_env=None, check_exit_code=True):
|
||||||
LOG.debug('Running cmd (SSH): %s', cmd)
|
sanitized_cmd = strutils.mask_password(cmd)
|
||||||
|
LOG.debug('Running cmd (SSH): %s', sanitized_cmd)
|
||||||
if addl_env:
|
if addl_env:
|
||||||
raise InvalidArgumentError(_('Environment not supported over SSH'))
|
raise InvalidArgumentError(_('Environment not supported over SSH'))
|
||||||
|
|
||||||
|
@ -254,7 +257,10 @@ def ssh_execute(ssh, cmd, process_input=None,
|
||||||
# NOTE(justinsb): This seems suspicious...
|
# NOTE(justinsb): This seems suspicious...
|
||||||
# ...other SSH clients have buffering issues with this approach
|
# ...other SSH clients have buffering issues with this approach
|
||||||
stdout = stdout_stream.read()
|
stdout = stdout_stream.read()
|
||||||
|
sanitized_stdout = strutils.mask_password(stdout)
|
||||||
stderr = stderr_stream.read()
|
stderr = stderr_stream.read()
|
||||||
|
sanitized_stderr = strutils.mask_password(stderr)
|
||||||
|
|
||||||
stdin_stream.close()
|
stdin_stream.close()
|
||||||
|
|
||||||
exit_status = channel.recv_exit_status()
|
exit_status = channel.recv_exit_status()
|
||||||
|
@ -264,11 +270,11 @@ def ssh_execute(ssh, cmd, process_input=None,
|
||||||
LOG.debug('Result was %s' % exit_status)
|
LOG.debug('Result was %s' % exit_status)
|
||||||
if check_exit_code and exit_status != 0:
|
if check_exit_code and exit_status != 0:
|
||||||
raise ProcessExecutionError(exit_code=exit_status,
|
raise ProcessExecutionError(exit_code=exit_status,
|
||||||
stdout=stdout,
|
stdout=sanitized_stdout,
|
||||||
stderr=stderr,
|
stderr=sanitized_stderr,
|
||||||
cmd=cmd)
|
cmd=sanitized_cmd)
|
||||||
|
|
||||||
return (stdout, stderr)
|
return (sanitized_stdout, sanitized_stderr)
|
||||||
|
|
||||||
|
|
||||||
def get_worker_count():
|
def get_worker_count():
|
||||||
|
|
|
@ -50,26 +50,37 @@ SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
|
||||||
SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
|
SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
|
||||||
|
|
||||||
|
|
||||||
# NOTE(flaper87): The following 3 globals are used by `mask_password`
|
# NOTE(flaper87): The following globals are used by `mask_password`
|
||||||
_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
|
_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
|
||||||
|
|
||||||
# NOTE(ldbragst): Let's build a list of regex objects using the list of
|
# NOTE(ldbragst): Let's build a list of regex objects using the list of
|
||||||
# _SANITIZE_KEYS we already have. This way, we only have to add the new key
|
# _SANITIZE_KEYS we already have. This way, we only have to add the new key
|
||||||
# to the list of _SANITIZE_KEYS and we can generate regular expressions
|
# to the list of _SANITIZE_KEYS and we can generate regular expressions
|
||||||
# for XML and JSON automatically.
|
# for XML and JSON automatically.
|
||||||
_SANITIZE_PATTERNS = []
|
_SANITIZE_PATTERNS_2 = []
|
||||||
_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
|
_SANITIZE_PATTERNS_1 = []
|
||||||
r'(<%(key)s>).*?(</%(key)s>)',
|
|
||||||
r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
|
# NOTE(amrith): Some regular expressions have only one parameter, some
|
||||||
r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])',
|
# have two parameters. Use different lists of patterns here.
|
||||||
r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?[\'"])'
|
_FORMAT_PATTERNS_1 = [r'(%(key)s\s*[=]\s*)[^\s^\'^\"]+']
|
||||||
'.*?([\'"])',
|
_FORMAT_PATTERNS_2 = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
|
||||||
r'(%(key)s\s*--?[A-z]+\s*)\S+(\s*)']
|
r'(%(key)s\s+[\"\']).*?([\"\'])',
|
||||||
|
r'([-]{2}%(key)s\s+)[^\'^\"^=^\s]+([\s]*)',
|
||||||
|
r'(<%(key)s>).*?(</%(key)s>)',
|
||||||
|
r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
|
||||||
|
r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])',
|
||||||
|
r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?'
|
||||||
|
'[\'"]).*?([\'"])',
|
||||||
|
r'(%(key)s\s*--?[A-z]+\s*)\S+(\s*)']
|
||||||
|
|
||||||
for key in _SANITIZE_KEYS:
|
for key in _SANITIZE_KEYS:
|
||||||
for pattern in _FORMAT_PATTERNS:
|
for pattern in _FORMAT_PATTERNS_2:
|
||||||
reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
|
reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
|
||||||
_SANITIZE_PATTERNS.append(reg_ex)
|
_SANITIZE_PATTERNS_2.append(reg_ex)
|
||||||
|
|
||||||
|
for pattern in _FORMAT_PATTERNS_1:
|
||||||
|
reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
|
||||||
|
_SANITIZE_PATTERNS_1.append(reg_ex)
|
||||||
|
|
||||||
|
|
||||||
def int_from_bool_as_string(subject):
|
def int_from_bool_as_string(subject):
|
||||||
|
@ -289,7 +300,12 @@ def mask_password(message, secret="***"):
|
||||||
if not any(key in message for key in _SANITIZE_KEYS):
|
if not any(key in message for key in _SANITIZE_KEYS):
|
||||||
return message
|
return message
|
||||||
|
|
||||||
secret = r'\g<1>' + secret + r'\g<2>'
|
substitute = r'\g<1>' + secret + r'\g<2>'
|
||||||
for pattern in _SANITIZE_PATTERNS:
|
for pattern in _SANITIZE_PATTERNS_2:
|
||||||
message = re.sub(pattern, secret, message)
|
message = re.sub(pattern, substitute, message)
|
||||||
|
|
||||||
|
substitute = r'\g<1>' + secret
|
||||||
|
for pattern in _SANITIZE_PATTERNS_1:
|
||||||
|
message = re.sub(pattern, substitute, message)
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
Loading…
Reference in New Issue