add output and bare functionality

This commit is contained in:
Leif Liddy 2022-10-30 15:58:03 +01:00 committed by Megan Wilhite
parent 2b20289349
commit f48161d357
3 changed files with 79 additions and 14 deletions

1
changelog/62978.added Normal file
View file

@ -0,0 +1 @@
Added output and bare functionality to export_key gpg module function

View file

@ -783,16 +783,15 @@ def import_key(text=None, filename=None, user=None, gnupghome=None):
def export_key( def export_key(
keyids=None, secret=False, user=None, gnupghome=None, use_passphrase=False keyids=None, secret=False, user=None, gnupghome=None, output=None, use_passphrase=False, bare=False,
): ):
""" """
Export a key from the GPG keychain Export a key from the GPG keychain
keyids keyids
The key ID(s) of the key(s) to be exported. Can be specified as a comma The key ID(s) of the key(s) to be exported. Can be specified as a comma
separated string or a list. Anything which GnuPG itself accepts to separated string or a list. Anything which GnuPG itself accepts to identify a key
identify a key - for example, the key ID or the fingerprint could be for example, the key ID, fingerprint, user ID or email address could be used.
used.
secret secret
Export the secret key identified by the ``keyids`` information passed. Export the secret key identified by the ``keyids`` information passed.
@ -805,12 +804,19 @@ def export_key(
gnupghome gnupghome
Specify the location where GPG keyring and related files are stored. Specify the location where GPG keyring and related files are stored.
output
The filename where the exported key data will be written to, default is standard out.
use_passphrase use_passphrase
Whether to use a passphrase with the signing key. Passphrase is received Whether to use a passphrase to export the secret key.
from Pillar. Passphrase is received from Pillar.
.. versionadded:: 3003 .. versionadded:: 3003
bare
If ``True``, return the (armored) exported key block as a string without the
standard comment/res dict.
CLI Example: CLI Example:
.. code-block:: bash .. code-block:: bash
@ -822,18 +828,38 @@ def export_key(
salt '*' gpg.export_key keyids="['3FAD9F1E','3FBD8F1E']" user=username salt '*' gpg.export_key keyids="['3FAD9F1E','3FBD8F1E']" user=username
""" """
ret = {"res": True}
gpg = _create_gpg(user, gnupghome) gpg = _create_gpg(user, gnupghome)
if isinstance(keyids, str): if isinstance(keyids, str):
keyids = keyids.split(",") keyids = keyids.split(",")
if use_passphrase: if secret and use_passphrase:
gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase") gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase")
if not gpg_passphrase: if not gpg_passphrase:
raise SaltInvocationError("gpg_passphrase not available in pillar.") raise SaltInvocationError("gpg_passphrase not available in pillar.")
ret = gpg.export_keys(keyids, secret, passphrase=gpg_passphrase) result = gpg.export_keys(keyids, secret, passphrase=gpg_passphrase)
else: else:
ret = gpg.export_keys(keyids, secret, expect_passphrase=False) result = gpg.export_keys(keyids, secret, expect_passphrase=False)
if output and result:
with salt.utils.files.flopen(output, "w") as fout:
fout.write(salt.utils.stringutils.to_str(result))
if result:
if not bare:
if output:
ret["comment"] = "Exported key data has been written to {}".format(output)
else:
ret["comment"] = result
else:
ret = result
else:
if not bare:
ret["res"] = False
else:
ret = False
return ret return ret

View file

@ -5,6 +5,7 @@
import datetime import datetime
import logging import logging
import pathlib
import shutil import shutil
import subprocess import subprocess
import time import time
@ -578,7 +579,7 @@ def test_export_key_without_passphrase(gpghome):
"salt.modules.gpg.gnupg.GPG.export_keys", "salt.modules.gpg.gnupg.GPG.export_keys",
MagicMock(return_value=GPG_TEST_PUB_KEY), MagicMock(return_value=GPG_TEST_PUB_KEY),
) as gnupg_export_keys: ) as gnupg_export_keys:
ret = gpg.export_key("xxxxxxxxxxxxxxxx") ret = gpg.export_key("xxxxxxxxxxxxxxxx", bare=True)
assert ret == GPG_TEST_PUB_KEY assert ret == GPG_TEST_PUB_KEY
gnupg_export_keys.assert_called_with( gnupg_export_keys.assert_called_with(
["xxxxxxxxxxxxxxxx"], ["xxxxxxxxxxxxxxxx"],
@ -614,7 +615,8 @@ def test_export_multiple_keys_without_passphrase(gpghome):
MagicMock(return_value=GPG_TEST_PUB_KEY), MagicMock(return_value=GPG_TEST_PUB_KEY),
) as gnupg_export_keys: ) as gnupg_export_keys:
ret = gpg.export_key( ret = gpg.export_key(
"xxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzz" "xxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzz",
bare=True,
) )
assert ret == GPG_TEST_PUB_KEY assert ret == GPG_TEST_PUB_KEY
gnupg_export_keys.assert_called_with( gnupg_export_keys.assert_called_with(
@ -654,7 +656,7 @@ def test_export_key_with_passphrase_without_gpg_passphrase_in_pillar(gpghome):
MagicMock(return_value=GPG_TEST_PUB_KEY), MagicMock(return_value=GPG_TEST_PUB_KEY),
) as gnupg_export_keys: ) as gnupg_export_keys:
with pytest.raises(SaltInvocationError): with pytest.raises(SaltInvocationError):
assert gpg.export_key("xxxxxxxxxxxxxxxx", use_passphrase=True) assert gpg.export_key("xxxxxxxxxxxxxxxx", secret=True, use_passphrase=True)
gnupg_export_keys.assert_not_called() gnupg_export_keys.assert_not_called()
@ -687,14 +689,50 @@ def test_export_key_with_passphrase_with_gpg_passphrase_in_pillar(gpghome):
"salt.modules.gpg.gnupg.GPG.export_keys", "salt.modules.gpg.gnupg.GPG.export_keys",
MagicMock(return_value=GPG_TEST_PUB_KEY), MagicMock(return_value=GPG_TEST_PUB_KEY),
) as gnupg_export_keys: ) as gnupg_export_keys:
ret = gpg.export_key("xxxxxxxxxxxxxxxx", use_passphrase=True) ret = gpg.export_key("xxxxxxxxxxxxxxxx", secret=True, use_passphrase=True, bare=True)
assert ret == GPG_TEST_PUB_KEY assert ret == GPG_TEST_PUB_KEY
# expected
gnupg_export_keys.assert_called_with( gnupg_export_keys.assert_called_with(
["xxxxxxxxxxxxxxxx"], ["xxxxxxxxxxxxxxxx"],
False, True,
passphrase=GPG_TEST_KEY_PASSPHRASE, passphrase=GPG_TEST_KEY_PASSPHRASE,
) )
def test_export_key_to_file_with_passphrase_with_gpg_passphrase_in_pillar(gpghome):
"""
Test gpg.export_key with passphrase and gpg_passphrase pillar
"""
_user_mock = {
"shell": "/bin/bash",
"workphone": "",
"uid": 0,
"passwd": "x",
"roomnumber": "",
"gid": 0,
"groups": ["root"],
"home": str(gpghome.path),
"fullname": "root",
"homephone": "",
"name": "root",
}
exported_keyfile = gpghome.path / "exported_key"
mock_opt = MagicMock(return_value="root")
pillar_mock = MagicMock(return_value=GPG_TEST_KEY_PASSPHRASE)
with patch.dict(gpg.__salt__, {"user.info": MagicMock(return_value=_user_mock)}):
with patch.dict(gpg.__salt__, {"config.option": mock_opt}), patch.dict(
gpg.__salt__, {"pillar.get": pillar_mock}
):
with patch(
"salt.modules.gpg.gnupg.GPG.export_keys",
MagicMock(return_value=GPG_TEST_PUB_KEY),
) as gnupg_export_keys:
ret = gpg.export_key(keyids=GPG_TEST_KEY_ID, secret=True, output=exported_keyfile, use_passphrase=True, bare=True)
assert ret == GPG_TEST_PUB_KEY
keyfile_contents = pathlib.Path(exported_keyfile).read_text()
assert keyfile_contents == GPG_TEST_PUB_KEY
def test_create_key_without_passphrase(gpghome): def test_create_key_without_passphrase(gpghome):
""" """