URL: https://github.com/freeipa/freeipa/pull/4964
Author: fcami
 Title: #4964: Remove paramiko usage from ipatests
Action: opened

PR body:
"""
MANUAL BACKPORT

Paramiko is not compatible with FIPS.
Migrate all tests using paramiko to the OpenSSH CLI SSH(1).

Fixes: https://pagure.io/freeipa/issue/8129

Note that https://pagure.io/freeipa/issue/8431 was filed as sshpass would need 
an enhancement to cover all OTP tests.

"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/4964/head:pr4964
git checkout pr4964
From 9043538e63de5ee1b597c433e13cbea14f61cd2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Wed, 22 Jul 2020 09:59:12 +0200
Subject: [PATCH 1/8] tasks: add run_ssh_cmd
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
A replacement is needed, and since what clients use is "ssh",
create a shim over it so that tests can leverage it.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/pytest_ipa/integration/tasks.py | 133 +++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
index 2ffaceb866..a3f7cc8386 100755
--- a/ipatests/pytest_ipa/integration/tasks.py
+++ b/ipatests/pytest_ipa/integration/tasks.py
@@ -30,6 +30,7 @@
 import itertools
 import shutil
 import copy
+import subprocess
 import tempfile
 import time
 from pipes import quote
@@ -2297,3 +2298,135 @@ def get_sssd_version(host):
     """Get sssd version on remote host."""
     version = host.run_command('sssd --version').stdout_text.strip()
     return parse_version(version)
+
+
+def run_ssh_cmd(
+    from_host=None, to_host=None, username=None, cmd=None,
+    auth_method=None, password=None, private_key_path=None,
+    expect_auth_success=True, expect_auth_failure=None,
+    verbose=True, connect_timeout=2, strict_host_key_checking=False
+):
+    """Runs an ssh connection from the controller to the host.
+       - auth_method can be either "password" or "key".
+       - In the first case, set password to the user's password ; in the
+         second case, set private_key_path to the path of the private key.
+       - If expect_auth_success or expect_auth_failure, analyze the ssh
+         client's log and check whether the selected authentication method
+         worked. expect_auth_failure takes precedence over expect_auth_success.
+       - If verbose, display the ssh client verbose log.
+       - Both expect_auth_success and verbose are True by default. Debugging
+         ssh client failures is next to impossible without the associated
+         debug log.
+       Possible enhancements:
+       - select which host to run from (currently: controller only)
+    """
+
+    if from_host is not None:
+        raise NotImplementedError(
+            "from_host must be None ; running from anywhere but the "
+            "controller is not implemented yet."
+        )
+
+    if expect_auth_failure:
+        expect_auth_success = False
+
+    if to_host is None or username is None or auth_method is None:
+        raise ValueError("host, username and auth_method are mandatory")
+    if cmd is None:
+        # cmd must run properly on all supported platforms.
+        # true(1) ("do nothing, successfully") is the obvious candidate.
+        cmd = "true"
+
+    if auth_method == "password":
+        if password is None:
+            raise ValueError(
+                "password is mandatory if auth_method == password"
+            )
+        ssh_cmd = (
+            "ssh",
+            "-v",
+            "-o", "PubkeyAuthentication=no",
+            "-o", "GSSAPIAuthentication=no",
+            "-o", "ConnectTimeout={connect_timeout}".format(
+                connect_timeout=connect_timeout
+            ),
+        )
+    elif auth_method == "key":
+        if private_key_path is None:
+            raise ValueError(
+                "private_key_path is mandatory if auth_method == key"
+            )
+        ssh_cmd = (
+            "ssh",
+            "-v",
+            "-o", "BatchMode=yes",
+            "-o", "PubkeyAuthentication=yes",
+            "-o", "GSSAPIAuthentication=no",
+            "-o", "ConnectTimeout={connect_timeout}".format(
+                connect_timeout=connect_timeout
+            ),
+        )
+    else:
+        raise ValueError(
+            "auth_method must either be password or key"
+        )
+
+    ssh_cmd_1 = list(ssh_cmd)
+    if strict_host_key_checking is True:
+        ssh_cmd_1.extend(("-o", "StrictHostKeyChecking=yes"))
+    else:
+        ssh_cmd_1.extend(("-o", "StrictHostKeyChecking=no"))
+    if auth_method == "password":
+        ssh_cmd_1 = list(("sshpass", "-p", password)) + ssh_cmd_1
+    elif auth_method == "key":
+        ssh_cmd_1.extend(("-i", private_key_path))
+    ssh_cmd_1.extend(("-l", username, to_host, cmd))
+
+    try:
+        if verbose:
+            output = "OpenSSH command: {sshcmd}".format(sshcmd=ssh_cmd_1)
+            logger.info(output)
+        remote_cmd = subprocess.Popen(
+            ssh_cmd_1,
+            shell=False,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE
+        )
+        while remote_cmd.poll() is None:
+            time.sleep(0.1)
+        return_code = remote_cmd.returncode
+        stderr = os.linesep.join(
+            str(line) for line in remote_cmd.stderr.readlines()
+        )
+        stdout = os.linesep.join(
+            str(line) for line in remote_cmd.stderr.readlines()
+        )
+        if verbose:
+            print_stdout = "Standard output: {stdout}".format(stdout=stdout)
+            print_stderr = "Standard error: {stderr}".format(stderr=stderr)
+            logger.info(print_stdout)
+            logger.info(print_stderr)
+    except Exception as e:
+        pytest.fail("Unable to run ssh command.", e)
+
+    if auth_method == "password":
+        if expect_auth_success is True:
+            assert "Authentication succeeded (keyboard-interactive)" in \
+                stderr
+            # do not assert the return code:
+            # it can be >0 if the command failed.
+        elif expect_auth_failure is True:
+            # sshpass return code: 5 for failed auth
+            assert return_code == 5
+            assert "Authentication succeeded" not in stderr
+    elif auth_method == "key":
+        if expect_auth_success is True:
+            assert "Authentication succeeded (publickey)" in stderr
+            # do not assert the return code:
+            # it can be >0 if the command failed.
+        elif expect_auth_failure is True:
+            # ssh return code: 255 for failed auth
+            assert return_code == 255
+            assert "Authentication succeeded" not in stderr
+            assert "No more authentication methods to try." in stderr
+    return (return_code, stdout, stderr)

From 3a1548f839940dd915c574fe1603814f7fc57511 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Wed, 22 Jul 2020 11:12:11 +0200
Subject: [PATCH 2/8] ipatests: test_commands: test_ssh_key_connection:
 Paramiko=>OpenSSH
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate test_ssh_key_connection to the OpenSSH CLI SSH(1).
Rationale: this is exactly what clients use.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_integration/test_commands.py | 32 ++++++----------------
 1 file changed, 9 insertions(+), 23 deletions(-)

diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
index bacde50416..1380a0fd8a 100644
--- a/ipatests/test_integration/test_commands.py
+++ b/ipatests/test_integration/test_commands.py
@@ -10,6 +10,7 @@
 import os
 import logging
 import random
+import shlex
 import ssl
 from itertools import chain, repeat
 import textwrap
@@ -609,12 +610,8 @@ def test_ssh_key_connection(self, tmpdir):
         """
         Integration test for https://pagure.io/SSSD/sssd/issue/3747
         """
-        if self.master.is_fips_mode:  # pylint: disable=no-member
-            pytest.skip("paramiko is not compatible with FIPS mode")
 
         test_user = 'test-ssh'
-        external_master_hostname = \
-            self.master.external_hostname
 
         pub_keys = []
 
@@ -624,37 +621,26 @@ def test_ssh_key_connection(self, tmpdir):
             with open(os.path.join(
                     tmpdir, 'ssh_priv_{}'.format(i)), 'w') as fp:
                 fp.write(ssh_key_pair[0])
+                fp.write(os.linesep)
 
         tasks.kinit_admin(self.master)
         self.master.run_command(['ipa', 'user-add', test_user,
                                  '--first=tester', '--last=tester'])
 
         keys_opts = ' '.join(['--ssh "{}"'.format(k) for k in pub_keys])
-        cmd = 'ipa user-mod {} {}'.format(test_user, keys_opts)
-        self.master.run_command(cmd)
+        self.master.run_command(
+            shlex.split('ipa user-mod {} {}'.format(test_user, keys_opts))
+        )
 
         # connect with first SSH key
         first_priv_key_path = os.path.join(tmpdir, 'ssh_priv_1')
         # change private key permission to comply with SS rules
         os.chmod(first_priv_key_path, 0o600)
 
-        sshcon = paramiko.SSHClient()
-        sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-
-        # first connection attempt is a workaround for
-        # https://pagure.io/SSSD/sssd/issue/3669
-        try:
-            sshcon.connect(external_master_hostname, username=test_user,
-                           key_filename=first_priv_key_path, timeout=1)
-        except (paramiko.AuthenticationException, paramiko.SSHException):
-            pass
-
-        try:
-            sshcon.connect(external_master_hostname, username=test_user,
-                           key_filename=first_priv_key_path, timeout=1)
-        except (paramiko.AuthenticationException,
-                paramiko.SSHException) as e:
-            pytest.fail('Authentication using SSH key not successful', e)
+        tasks.run_ssh_cmd(
+            to_host=self.master.external_hostname, username=test_user,
+            auth_method="key", private_key_path=first_priv_key_path
+        )
 
         journal_cmd = ['journalctl', '--since=today', '-u', 'sshd']
         result = self.master.run_command(journal_cmd)

From 17a4028fc77db873fd45a83361dd7e9ec3d54597 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Thu, 23 Jul 2020 10:53:48 +0200
Subject: [PATCH 3/8] ipatests: test_user_permissions:
 test_selinux_user_optimized Paramiko=>OpenSSH
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate test_selinux_user_optimized to the OpenSSH CLI SSH(1).
Rationale: this is exactly what clients use.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 .../test_integration/test_user_permissions.py | 39 +++++++------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/ipatests/test_integration/test_user_permissions.py b/ipatests/test_integration/test_user_permissions.py
index 42f87c5949..14aa4b3887 100644
--- a/ipatests/test_integration/test_user_permissions.py
+++ b/ipatests/test_integration/test_user_permissions.py
@@ -4,7 +4,6 @@
 
 from __future__ import absolute_import
 
-import paramiko
 import pytest
 
 from ipaplatform.osinfo import osinfo
@@ -84,42 +83,32 @@ def test_selinux_user_optimized(self):
 
         Related ticket https://pagure.io/SSSD/sssd/issue/3819.
         """
-        if self.master.is_fips_mode:  # pylint: disable=no-member
-            pytest.skip("paramiko is not compatible with FIPS mode")
 
         # Scenario: add an IPA user with non-default home dir, login through
         # ssh as this user and check that there is a SELinux user mapping
         # for the user with `semanage login -l`.
 
-        # kinit admin
-        tasks.kinit_admin(self.master)
-
-        testuser = 'testuser_selinux'
+        test_user = 'testuser_selinux'
         password = 'Secret123'
-        testuser_password_confirmation = "%s\n%s\n" % (password,
-                                                       password)
-        self.master.run_command(['ipa', 'user-add', testuser,
-                                 '--first', testuser,
-                                 '--last', testuser,
-                                 '--password',
-                                 '--homedir',
-                                 '/root/{}'.format(testuser)],
-                                stdin_text=testuser_password_confirmation)
 
-        # login to the system
-        client = paramiko.SSHClient()
-        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-        client.connect(self.master.hostname,
-                       username=testuser,
-                       password=password)
-        client.close()
+        tasks.kinit_admin(self.master)
+        tasks.create_active_user(
+            self.master, test_user, password=password,
+            extra_args=['--homedir', '/root/{}'.format(test_user)]
+        )
+
+        tasks.run_ssh_cmd(
+            to_host=self.master.external_hostname, username=test_user,
+            auth_method="password", password=password
+        )
 
         # check if user listed in output
         cmd = self.master.run_command(['semanage', 'login', '-l'])
-        assert testuser in cmd.stdout_text
+        assert test_user in cmd.stdout_text
 
         # call ipa user-del
-        self.master.run_command(['ipa', 'user-del', testuser])
+        tasks.kinit_admin(self.master)
+        self.master.run_command(['ipa', 'user-del', test_user])
 
     def test_stageuser_show_as_alternate_admin(self):
         """

From e36526a306ae3627992fe2ee8a0b411164a9b4ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Fri, 24 Jul 2020 13:26:47 +0200
Subject: [PATCH 4/8] ipatests: test_commands: test_ssh_from_controller:
 refactor
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

test_ssh_from_controller does not use methods provided by tasks.py.
Refactor using those methods.

Related: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>

Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_integration/test_commands.py | 26 +++++++++++-----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
index 1380a0fd8a..c7b07fd929 100644
--- a/ipatests/test_integration/test_commands.py
+++ b/ipatests/test_integration/test_commands.py
@@ -901,12 +901,14 @@ def test_ssh_from_controller(self):
         if sssd_version < platform_tasks.parse_ipa_version('2.2.0'):
             pytest.xfail(reason="sssd 2.2.0 unavailable in F29 nightly")
 
-        username = "testuser" + str(random.randint(200000, 9999999))
         # add ldap_deref_threshold=0 to /etc/sssd/sssd.conf
         sssd_conf_backup = tasks.FileBackup(self.master, paths.SSSD_CONF)
         with tasks.remote_sssd_config(self.master) as sssd_config:
             sssd_config.edit_domain(
                 self.master.domain, 'ldap_deref_threshold', 0)
+
+        test_user = "testuser" + str(random.randint(200000, 9999999))
+        password = "Secret123"
         try:
             self.master.run_command(['systemctl', 'restart', 'sssd.service'])
 
@@ -914,22 +916,20 @@ def test_ssh_from_controller(self):
             tasks.kinit_admin(self.master)
 
             # add ipa user
-            cmd = ['ipa', 'user-add',
-                   '--first', username,
-                   '--last', username,
-                   '--password', username]
-            input_passwd = 'Secret123\nSecret123\n'
-            cmd_output = self.master.run_command(cmd, stdin_text=input_passwd)
-            assert 'Added user "%s"' % username in cmd_output.stdout_text
-            input_passwd = 'Secret123\nSecret123\nSecret123\n'
-            self.master.run_command(['kinit', username],
-                                    stdin_text=input_passwd)
+            tasks.create_active_user(
+                self.master, test_user, password=password
+            )
+            tasks.kdestroy_all(self.master)
+            tasks.kinit_as_user(
+                self.master, test_user, password
+            )
+            tasks.kdestroy_all(self.master)
 
             client = paramiko.SSHClient()
             client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
             client.connect(self.master.hostname,
-                           username=username,
-                           password='Secret123')
+                           username=test_user,
+                           password=password)
             client.close()
         finally:
             sssd_conf_backup.restore()

From 996bf588952ebd403465bfe8a7b5c3e7c1538a6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Fri, 24 Jul 2020 15:18:29 +0200
Subject: [PATCH 5/8] ipatests: test_commands: test_ssh_from_controller:
 Paramiko=>OpenSSH
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate test_ssh_from_controller to the OpenSSH CLI SSH(1).
Rationale: this is exactly what clients use.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_integration/test_commands.py | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
index c7b07fd929..f088aecab9 100644
--- a/ipatests/test_integration/test_commands.py
+++ b/ipatests/test_integration/test_commands.py
@@ -892,8 +892,6 @@ def test_ssh_from_controller(self):
         3. add an ipa user
         4. ssh from controller to master using the user created in step 3
         """
-        if self.master.is_fips_mode:  # pylint: disable=no-member
-            pytest.skip("paramiko is not compatible with FIPS mode")
 
         cmd = self.master.run_command(['sssd', '--version'])
         sssd_version = platform_tasks.parse_ipa_version(
@@ -925,12 +923,11 @@ def test_ssh_from_controller(self):
             )
             tasks.kdestroy_all(self.master)
 
-            client = paramiko.SSHClient()
-            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-            client.connect(self.master.hostname,
-                           username=test_user,
-                           password=password)
-            client.close()
+            tasks.run_ssh_cmd(
+                to_host=self.master.external_hostname, username=test_user,
+                auth_method="password", password=password
+            )
+
         finally:
             sssd_conf_backup.restore()
             self.master.run_command(['systemctl', 'restart', 'sssd.service'])

From 4f4a5d9c6617cd667ca8c9e7f7bbca74df44d3ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Fri, 24 Jul 2020 16:23:28 +0200
Subject: [PATCH 6/8] ipatests: test_commands: test_login_wrong_password:
 Paramiko=>OpenSSH
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate test_login_wrong_password to the OpenSSH CLI SSH(1).
Rationale: this is exactly what clients use.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_integration/test_commands.py | 23 +++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
index f088aecab9..a9101b6317 100644
--- a/ipatests/test_integration/test_commands.py
+++ b/ipatests/test_integration/test_commands.py
@@ -15,7 +15,6 @@
 from itertools import chain, repeat
 import textwrap
 import time
-import paramiko
 import pytest
 from subprocess import CalledProcessError
 
@@ -1183,17 +1182,19 @@ def test_login_wrong_password(self, user_creation_deletion):
             pytest.xfail('Fix is part of sssd 2.3.0 and is'
                          ' available from fedora32 onwards')
 
-        sshconn = paramiko.SSHClient()
-        sshconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-        since = time.strftime('%H:%M:%S')
-        try:
-            sshconn.connect(self.master.hostname,
-                            username=self.testuser,
-                            password='WrongPassword')
-        except paramiko.AuthenticationException:
-            pass
+        # start to look at logs a bit before "now"
+        # https://pagure.io/freeipa/issue/8432
+        since = time.strftime(
+            '%H:%M:%S', (datetime.now() - timedelta(seconds=10)).timetuple()
+        )
+
+        password = 'WrongPassword'
 
-        sshconn.close()
+        tasks.run_ssh_cmd(
+            to_host=self.master.external_hostname, username=self.testuser,
+            auth_method="password", password=password,
+            expect_auth_failure=True
+        )
 
         # check if proper message logged
         exp_msg = ("pam_sss(sshd:auth): received for user {}: 7"

From fe755d9472a0a6693273b30c9745a233189d732f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Mon, 27 Jul 2020 09:49:59 +0200
Subject: [PATCH 7/8] ipatests: ui_driver: convert run_cmd_on_ui_host to
 tasks.py::run_ssh_cmd
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate run_cmd_on_ui_host to the OpenSSH CLI SSH(1) using
tasks.py's run_ssh_cmd.
Rationale: this is exactly what clients use.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 70e8e7b256..dc02a0eaa3 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -32,7 +32,6 @@
 from functools import wraps
 from urllib.error import URLError
 
-import paramiko
 import pytest
 
 try:
@@ -61,7 +60,9 @@
     NO_YAML = True
 
 from ipaplatform.paths import paths
-from ipaplatform.tasks import tasks
+
+from ipatests.pytest_ipa.integration import tasks
+
 
 ENV_MAP = {
     'MASTER': 'ipa_server',
@@ -1972,26 +1973,16 @@ def run_cmd_on_ui_host(self, cmd):
 
         cmd (str): command to run
         """
-        if tasks.is_fips_enabled():
-            pytest.skip("paramiko is not compatible with FIPS mode")
 
         login = self.config.get('ipa_admin')
         hostname = self.config.get('ipa_server')
         password = self.config.get('ipa_password')
 
-        try:
-            ssh = paramiko.SSHClient()
-            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-            ssh.connect(hostname=hostname, username=login, password=password)
-            ssh.exec_command(cmd)
-        except paramiko.AuthenticationException:
-            self.skip('Authentication to server {} failed'.format(hostname))
-        except paramiko.SSHException as e:
-            self.skip('Unable to establish SSH connection: {}'.format(e))
-        except Exception as e:
-            self.skip('Unable to proceed: {}'.format(e))
-        finally:
-            ssh.close()
+        tasks.run_ssh_cmd(
+            to_host=hostname, username=login,
+            auth_method="password", password=password,
+            cmd=cmd
+        )
 
     @dismiss_unexpected_alert
     def has_class(self, el, cls):

From 7537a378f5dced82ab5c14f9ed2a282b375ef46c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fc...@redhat.com>
Date: Mon, 27 Jul 2020 12:13:25 +0200
Subject: [PATCH 8/8] ipatests: test_otp: convert test_2fa_enable_single_prompt
 to run_ssh_cmd
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Paramiko is not compatible with FIPS.
Migrate test_2fa_enable_single_prompt to the OpenSSH CLI SSH(1).
Rationale: this is exactly what clients use.
Also add a warning when test_2fa_disable_single_prompt is executed in FIPS mode.

Fixes: https://pagure.io/freeipa/issue/8129
Signed-off-by: François Cami <fc...@redhat.com>
Reviewed-By: Mohammad Rizwan <myu...@redhat.com>
Reviewed-By: Michal Polovka <mpolo...@redhat.com>
---
 ipatests/test_integration/test_otp.py | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/ipatests/test_integration/test_otp.py b/ipatests/test_integration/test_otp.py
index cbb602cc0d..b2e65af1b6 100644
--- a/ipatests/test_integration/test_otp.py
+++ b/ipatests/test_integration/test_otp.py
@@ -6,6 +6,7 @@
 import base64
 import logging
 import paramiko
+import pytest
 import re
 import time
 import textwrap
@@ -231,6 +232,7 @@ def test_2fa_enable_single_prompt(self):
         then during ssh it should be prompted with given message
         for first and second factor at once.
         """
+
         master = self.master
         USER1 = 'sshuser1'
         sssd_conf_backup = tasks.FileBackup(master, paths.SSSD_CONF)
@@ -248,10 +250,11 @@ def test_2fa_enable_single_prompt(self):
             otpuid, totp = add_otptoken(master, USER1, otptype='totp')
             master.run_command(['ipa', 'otptoken-show', otpuid])
             otpvalue = totp.generate(int(time.time())).decode('ascii')
-            answers = {
-                first_prompt: '{0}{1}'.format(PASSWORD, otpvalue),
-            }
-            ssh_2f(master.hostname, USER1, answers)
+            password = '{0}{1}'.format(PASSWORD, otpvalue)
+            tasks.run_ssh_cmd(
+                to_host=self.master.external_hostname, username=USER1,
+                auth_method="password", password=password
+            )
             # check if user listed in output
             cmd = self.master.run_command(['semanage', 'login', '-l'])
             assert USER1 in cmd.stdout_text
@@ -268,7 +271,13 @@ def test_2fa_disable_single_prompt(self):
         When [prompting/2fa/sshd] with single_prompt = False is set
         then during ssh it should be prompted with given message
         for first factor and then for second factor.
+
+        This requires paramiko until the 2-prompt sshpass RFE is
+        fulfilled: https://sourceforge.net/p/sshpass/feature-requests/5/
         """
+        if self.master.is_fips_mode:  # pylint: disable=no-member
+            pytest.skip("paramiko is not compatible with FIPS mode")
+
         master = self.master
         USER2 = 'sshuser2'
         sssd_conf_backup = tasks.FileBackup(master, paths.SSSD_CONF)
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org

Reply via email to