Fixed GPG pillar decryption.

1. Returned back the ability to decrypt raw encrypted data containing no
begin/end marks.
2. Remove trailing newlines if decrypted in a new 'multi' way
implemented in #45781
This commit is contained in:
Dmitry Kuzmenko 2018-03-14 15:49:45 +03:00
parent 7e5ac41ef6
commit 0f482b7633
No known key found for this signature in database
GPG Key ID: 4C7CAD30C95651DA
2 changed files with 16 additions and 13 deletions

View File

@ -263,13 +263,12 @@ def _get_key_dir():
return gpg_keydir
def _decrypt_ciphertext(matchobj):
def _decrypt_ciphertext(cipher):
'''
Given a block of ciphertext as a string, and a gpg object, try to decrypt
the cipher and return the decrypted string. If the cipher cannot be
decrypted, log the error, and return the ciphertext back out.
'''
cipher = matchobj.group()
if six.PY3:
cipher = cipher.encode(__salt_system_encoding__)
cmd = [_get_gpg_exec(), '--homedir', _get_key_dir(), '--status-fd', '2',
@ -294,7 +293,14 @@ def _decrypt_ciphertext(matchobj):
def _decrypt_ciphertexts(cipher, translate_newlines=False):
if translate_newlines:
cipher = cipher.replace(r'\n', '\n')
return GPG_CIPHERTEXT.sub(_decrypt_ciphertext, cipher)
ret, num = GPG_CIPHERTEXT.subn(lambda m: _decrypt_ciphertext(m.group()), cipher)
if num > 0:
# Remove trailing newlines. Without if crypted value initially specified as a YAML multiline
# it will conain unexpected trailing newline.
return ret.rstrip('\n')
else:
# Possibly just encrypted data without begin/end marks
return _decrypt_ciphertext(cipher)
def _decrypt_object(obj, translate_newlines=False):

View File

@ -20,11 +20,9 @@ from salt.exceptions import SaltRenderError
@skipIf(NO_MOCK, NO_MOCK_REASON)
class GPGTestCase(TestCase, LoaderModuleMockMixin):
'''
unit test GPG renderer
'''
def setup_loader_modules(self):
return {gpg: {}}
@ -46,29 +44,30 @@ class GPGTestCase(TestCase, LoaderModuleMockMixin):
'''
key_dir = '/etc/salt/gpgkeys'
secret = 'Use more salt.'
crypted = '-----BEGIN PGP MESSAGE-----!@#$%^&*()_+-----END PGP MESSAGE-----'
crypted_long = '-----BEGIN PGP MESSAGE-----!@#$%^&*()_+-----END PGP MESSAGE-----'
crypted_short = '!@#$%^&*()_+'
multisecret = 'password is {0} and salt is {0}'.format(secret)
multicrypted = 'password is {0} and salt is {0}'.format(crypted)
multicrypted = 'password is {0} and salt is {0}'.format(crypted_long)
class GPGDecrypt(object):
def communicate(self, *args, **kwargs):
return [secret, None]
class GPGNotDecrypt(object):
def communicate(self, *args, **kwargs):
return [None, 'decrypt error']
with patch('salt.renderers.gpg._get_key_dir', MagicMock(return_value=key_dir)), \
patch('salt.utils.path.which', MagicMock()):
with patch('salt.renderers.gpg.Popen', MagicMock(return_value=GPGDecrypt())):
self.assertEqual(gpg._decrypt_ciphertexts(crypted), secret)
self.assertEqual(gpg._decrypt_ciphertexts(crypted_short), secret)
self.assertEqual(gpg._decrypt_ciphertexts(crypted_long), secret)
self.assertEqual(
gpg._decrypt_ciphertexts(multicrypted), multisecret)
with patch('salt.renderers.gpg.Popen', MagicMock(return_value=GPGNotDecrypt())):
self.assertEqual(gpg._decrypt_ciphertexts(crypted), crypted)
self.assertEqual(gpg._decrypt_ciphertexts(crypted_short), crypted_short)
self.assertEqual(gpg._decrypt_ciphertexts(crypted_long), crypted_long)
self.assertEqual(
gpg._decrypt_ciphertexts(multicrypted), multicrypted)
@ -76,7 +75,6 @@ class GPGTestCase(TestCase, LoaderModuleMockMixin):
'''
test _decrypt_object
'''
secret = 'Use more salt.'
crypted = '-----BEGIN PGP MESSAGE-----!@#$%^&*()_+-----END PGP MESSAGE-----'
@ -97,7 +95,6 @@ class GPGTestCase(TestCase, LoaderModuleMockMixin):
'''
test render
'''
key_dir = '/etc/salt/gpgkeys'
secret = 'Use more salt.'
crypted = '-----BEGIN PGP MESSAGE-----!@#$%^&*()_+'