Beispiel #1
0
 def test_case_senitivity(self, multihost, case_sensitive_sudorule,
                          enable_sss_sudo_nsswitch,
                          set_case_sensitive_false):
     """
     @Title: sudo: Verify case sensitivity in sudo responder
     """
     # pylint: disable=unused-argument
     _pytest_fixtures = [case_sensitive_sudorule, enable_sss_sudo_nsswitch,
                         set_case_sensitive_false]
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("%s failed to login" % 'capsuser-1')
     else:
         (stdout, _, exit_status) = ssh.execute_cmd('sudo -l')
         result = []
         assert exit_status == 0
         for line in stdout.readlines():
             if 'NOPASSWD' in line:
                 line.strip()
                 result.append(line.strip('(root) NOPASSWD: '))
         assert '/usr/bin/less\n' in result
         assert '/usr/bin/more\n' in result
         ssh.close()
Beispiel #2
0
 def test_refresh_expired_rule(self, multihost,
                               enable_sss_sudo_nsswitch,
                               generic_sudorule,
                               set_entry_cache_sudo_timeout):
     """
     @Title: sudo: Verify refreshing expired sudo rules
     do not crash sssd_sudo
     """
     # pylint: disable=unused-argument
     _pytest_fixtures = [enable_sss_sudo_nsswitch, generic_sudorule,
                         set_entry_cache_sudo_timeout]
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("%s failed to login" % 'foo1')
     else:
         print("Executing %s command as %s user" % ('sudo -l', 'foo1'))
         (_, _, exit_status) = ssh.execute_cmd('sudo -l')
         assert exit_status == 0
         time.sleep(30)
         if exit_status != 0:
             journalctl_cmd = 'journalctl -x -n 100 --no-pager'
             multihost.master[0].run_command(journalctl_cmd)
             pytest.fail("%s cmd failed for user %s" % ('sudo -l', 'foo1'))
         ssh.close()
Beispiel #3
0
 def test_ssh_user_login(self, multihost):
     """Check ssh login as LDAP user with Kerberos credentials """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo1'))
     else:
         assert True
         ssh.close()
Beispiel #4
0
 def test_ssh_login_kcm(self, multihost, enable_kcm):
     """ Verify ssh logins are successuful with kcm as default """
     # pylint: disable=unused-argument
     _pytest_fixture = [enable_kcm]
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         journalctl_cmd = 'journalctl -u sssd -n 50 --no-pager'
         multihost.master[0].run_command(journalctl_cmd)
         pytest.fail("Authentication Failed as user %s" % ('foo4'))
     else:
         assert True
         ssh.close()
Beispiel #5
0
    def test_kcm_debug_level_set(self, multihost, enable_kcm):
        """
        @Title: kcm: After kcm section with debug
        level set restaring sssd-kcm service enables kcm debugging

        @Description: Test that just adding a [kcm] section and restarting
        the kcm service enables debugging without having to restart the
        whole sssd
        """
        # Start from a known-good state where the configuration is refreshed
        # by the monitor and logging is completely disabled
        multihost.master[0].service_sssd('stop')
        self._stop_kcm(multihost)
        self._remove_kcm_log_file(multihost)
        set_param(multihost, 'kcm', 'debug_level', '0')
        multihost.master[0].service_sssd('start')
        self._start_kcm(multihost)

        log_lines_pre = self._kcm_log_length(multihost)

        # Debugging is disabled, kinit and make sure that no debug messages
        # were produced
        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo3'))
        else:
            ssh.execute_cmd('kdestroy')
            ssh.close()

        log_lines_nodebug = self._kcm_log_length(multihost)
        assert log_lines_nodebug == log_lines_pre

        # Enable debugging, restart only the kcm service, make sure some
        # debug messages were produced
        set_param(multihost, 'kcm', 'debug_level', '9')
        self._restart_kcm(multihost)

        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo3'))
        else:
            ssh.execute_cmd('kdestroy')
            ssh.close()

        log_lines_debug = self._kcm_log_length(multihost)
        assert log_lines_debug > log_lines_pre + 100
Beispiel #6
0
    def test_kcm_debug_level_set(self, multihost, enable_kcm):
        """
        @Title: kcm: After kcm section with debug
        level set restaring sssd-kcm service enables kcm debugging

        @Description: Test that just adding a [kcm] section and restarting
        the kcm service enables debugging without having to restart the
        whole sssd
        """
        # Start from a known-good state where the configuration is refreshed
        # by the monitor and logging is completely disabled
        multihost.master[0].service_sssd('stop')
        self._stop_kcm(multihost)
        self._remove_kcm_log_file(multihost)
        set_param(multihost, 'kcm', 'debug_level', '0')
        multihost.master[0].service_sssd('start')
        self._start_kcm(multihost)

        log_lines_pre = self._kcm_log_length(multihost)

        # Debugging is disabled, kinit and make sure that no debug messages
        # were produced
        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo3'))
        else:
            ssh.execute_cmd('kdestroy')
            ssh.close()

        log_lines_nodebug = self._kcm_log_length(multihost)
        assert log_lines_nodebug == log_lines_pre

        # Enable debugging, restart only the kcm service, make sure some
        # debug messages were produced
        set_param(multihost, 'kcm', 'debug_level', '9')
        self._restart_kcm(multihost)

        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo3'))
        else:
            ssh.execute_cmd('kdestroy')
            ssh.close()

        log_lines_debug = self._kcm_log_length(multihost)
        assert log_lines_debug > log_lines_pre + 100
    def test_0023_ldapldap(self, multihost, multidomain_sssd):
        """
         @Title: IDM-SSSD-TC: ldap_provider: test_for_multidomain: Login time
        increases strongly while authenticating against a user from second
        domain
        Automation of BZ694905

         multidomain_sssd(domains='ldap_ldap')
         """
        multidomain_sssd(domains='ldap_ldap')
        client_tools = sssdTools(multihost.client[0])
        for idx in range(2):
            params = {
                'ldap_search_base': 'dc=example%d,dc=test' % idx,
                'ldap_tls_reqcert': 'demand'
            }
            domain_section = 'domain/ldap%d' % (idx + 1)
            client_tools.sssd_conf(domain_section, params)
        domains = ['ldap1, ldap2', 'ldap2, ldap1']
        sssd_params = {'reconnection_retries': '3', 'sbus_timeout': '30'}
        client_tools.sssd_conf('sssd', sssd_params)
        for domain in domains:
            sssd_params = {'domains': domain}
            client_tools.sssd_conf('sssd', sssd_params)
            multihost.client[0].service_sssd('stop')
            client_tools.remove_sss_cache('/var/lib/sss/db')
            ret = multihost.client[0].service_sssd('start')
            assert ret == 0
            suffix = ['p', 'q']
            timer = []
            for dom in range(2):
                t1 = datetime.datetime.now()
                starttime = t1.second
                print("start time = ", starttime)
                user = '******' % (suffix[dom], dom + 1)
                print("user ="******"end time = ", endtime)
                    timer.append(endtime - starttime)
            print(timer)
Beispiel #8
0
def subid_generate(session_multihost, request):
    """
    Generate subid for user admin
    """
    user = "******"
    test_password = "******"
    ssh1 = SSHClient(session_multihost.client[0].ip,
                     username=user, password=test_password)
    (result, result1, exit_status) = ssh1.execute_cmd('kinit',
                                                      stdin=test_password)
    assert exit_status == 0
    (result, result1, exit_status) = ssh1.exec_command(f"ipa "
                                                       f" subid-generate"
                                                       f"  --owner={user}")
    ssh1.close()
Beispiel #9
0
def ipa_subid_find(multihost):
    ssh1 = SSHClient(multihost.client[0].ip,
                     username=user,
                     password=test_password)
    (result, result1, exit_status) = ssh1.exec_command(f"ipa  "
                                                       f"subid-find"
                                                       f"  --owner  "
                                                       f"{user}")
    user_details = result1.readlines()
    global uid_start, uid_range, gid_start, gid_range
    uid_start = int(user_details[5].split(': ')[1].split('\n')[0])
    uid_range = int(user_details[6].split(': ')[1].split('\n')[0])
    gid_start = int(user_details[7].split(': ')[1].split('\n')[0])
    gid_range = int(user_details[8].split(': ')[1].split('\n')[0])
    ssh1.close()
Beispiel #10
0
 def test_ssh_login_kcm(self, multihost, enable_kcm):
     """ Verify ssh logins are successuful with kcm as default """
     # pylint: disable=unused-argument
     _pytest_fixture = [enable_kcm]
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         journalctl_cmd = 'journalctl -u sssd -n 50 --no-pager'
         multihost.master[0].run_command(journalctl_cmd)
         pytest.fail("Authentication Failed as user %s" % ('foo4'))
     else:
         assert True
         ssh.close()
Beispiel #11
0
 def test_offline_ssh_login(self, multihost):
     """
     :title: Login: Verify offline ssh login
     :id: 90e9a834-a1f9-4bef-bdae-57a7b411cce4
     """
     multihost.master[0].transport.get_file('/etc/sssd/sssd.conf',
                                            '/tmp/sssd.conf')
     sssdconfig = ConfigParser.RawConfigParser()
     sssdconfig.read('/tmp/sssd.conf')
     domain_section = "%s/%s" % ('domain', 'EXAMPLE.TEST')
     if domain_section in sssdconfig.sections():
         sssdconfig.set(domain_section, 'cache_credentials', 'True')
         sssdconfig.set(domain_section, 'krb5_store_password_if_offline',
                        'True')
         sssdconfig.set('pam', 'offline_credentials_expiration', '0')
         with open('/tmp/sssd.conf', "w") as fd:
             sssdconfig.write(fd)
     else:
         print("Could not fetch sssd.conf")
         assert False
     multihost.master[0].transport.put_file('/tmp/sssd.conf',
                                            '/etc/sssd/sssd.conf')
     multihost.master[0].service_sssd('restart')
     time.sleep(5)
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Unable to authenticate as %s" % ('foo4'))
     else:
         ssh.close()
         stop_dirsrv = 'systemctl stop dirsrv@example1'
         stop_krb5kdc = 'systemctl stop krb5kdc'
         multihost.master[0].run_command(stop_dirsrv)
         multihost.master[0].run_command(stop_krb5kdc)
         try:
             ssh = SSHClient(multihost.master[0].sys_hostname,
                             username='******',
                             password='******')
         except paramiko.ssh_exception.AuthenticationException:
             pytest.fail("Unable to authenticate as %s" % ('foo4'))
         else:
             ssh.close()
             start_dirsrv = 'systemctl start dirsrv@example1'
             start_krb5kdc = 'systemctl start krb5kdc'
             multihost.master[0].run_command(start_dirsrv)
             multihost.master[0].run_command(start_krb5kdc)
Beispiel #12
0
    def test_kdestroy_retval(self, multihost, enable_kcm):
        """
        @Title: kcm: Test that destroying an empty cache does
        not return a non-zero return code
        """
        ssh = SSHClient(multihost.master[0].sys_hostname,
                        username='******', password='******')

        (_, _, exit_status) = ssh.execute_cmd('kdestroy')
        assert exit_status == 0
        # Run the command again in case there was something in the ccache
        # previously
        (_, _, exit_status) = ssh.execute_cmd('kdestroy')
        assert exit_status == 0

        ssh.close()
Beispiel #13
0
 def test_kinit(self, multihost):
     """ Run kinit after user login """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo2'))
     else:
         (_, _, exit_status) = ssh.execute_cmd(args='kinit',
                                               stdin='Secret123')
         assert exit_status == 0
         (stdout, _, _) = ssh.execute_cmd('klist')
         for line in stdout.readlines():
             print(line)
             assert exit_status == 0
             ssh.close()
Beispiel #14
0
 def test_kinit(self, multihost):
     """ Run kinit after user login """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo2'))
     else:
         (_, _, exit_status) = ssh.execute_cmd(args='kinit',
                                               stdin='Secret123')
         assert exit_status == 0
         (stdout, _, _) = ssh.execute_cmd('klist')
         for line in stdout.readlines():
             print(line)
             assert exit_status == 0
             ssh.close()
Beispiel #15
0
    def test_kdestroy_retval(self, multihost, enable_kcm):
        """
        @Title: kcm: Test that destroying an empty cache does
        not return a non-zero return code
        """
        ssh = SSHClient(multihost.master[0].sys_hostname,
                        username='******', password='******')

        (_, _, exit_status) = ssh.execute_cmd('kdestroy')
        assert exit_status == 0
        # Run the command again in case there was something in the ccache
        # previously
        (_, _, exit_status) = ssh.execute_cmd('kdestroy')
        assert exit_status == 0

        ssh.close()
Beispiel #16
0
    def test_kcm_peruid_quota(self, multihost, enable_kcm,
                              create_many_user_principals):
        """
        :title: kcm: Make sure the quota limits a client, but only that client
        :id: 3ac8f62e-05e4-4ca7-b588-145fd6258c2a
        """
        # It is easier to keep these tests stable and independent from others
        # if they start from a clean slate
        self._remove_secret_db(multihost)

        ssh_foo2 = SSHClient(multihost.master[0].sys_hostname,
                             username='******',
                             password='******')
        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
                             username='******',
                             password='******')

        # The loop would request 63 users, plus there is foo3 we authenticated
        # earlier, so this should exactly deplete the quota, but should succeed
        for i in range(1, 64):
            username = "******" % i
            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
                                                       stdin='Secret123')
            assert exit_status == 0

        # this kinit should be exactly one over the peruid limit
        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
                                                   stdin='Secret123')
        assert exit_status != 0

        # Since this is a per-uid limit, another user should be able to kinit
        # just fine
        (_, _, exit_status) = ssh_foo2.execute_cmd('kinit user0064',
                                                   stdin='Secret123')
        assert exit_status == 0

        # kdestroy as the original user, the quota should allow a subsequent
        # kinit
        ssh_foo3.execute_cmd('kdestroy -A')
        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
                                                   stdin='Secret123')
        assert exit_status == 0

        ssh_foo2.execute_cmd('kdestroy -A')
        ssh_foo2.close()
        ssh_foo3.execute_cmd('kdestroy -A')
        ssh_foo3.close()
Beispiel #17
0
 def test_timed_sudoers_entry(self, multihost, backupsssdconf,
                              timed_sudoers):
     """
     :title: sudo: sssd accepts timed entries without minutes and or
      seconds to attribute
     :id: 5103a796-6c7f-4af0-b7b8-64c7338f0934
     """
     # pylint: disable=unused-argument
     tools = sssdTools(multihost.client[0])
     multihost.client[0].service_sssd('stop')
     tools.remove_sss_cache('/var/lib/sss/db/')
     sudo_base = 'ou=sudoers,dc=example,dc=test'
     sudo_uri = "ldap://%s" % multihost.master[0].sys_hostname
     params = {
         'ldap_sudo_search_base': sudo_base,
         'ldap_uri': sudo_uri,
         'sudo_provider': "ldap"
     }
     domain_section = 'domain/%s' % ds_instance_name
     tools.sssd_conf(domain_section, params, action='update')
     section = "sssd"
     sssd_params = {'services': 'nss, pam, sudo'}
     tools.sssd_conf(section, sssd_params, action='update')
     multihost.client[0].service_sssd('start')
     try:
         ssh = SSHClient(multihost.client[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("%s failed to login" % 'foo1')
     else:
         print("Executing %s command as %s user" %
               ('sudo -l', '*****@*****.**'))
         (std_out, _, exit_status) = ssh.execute_cmd('id')
         for line in std_out.readlines():
             print(line)
         (std_out, _, exit_status) = ssh.execute_cmd('sudo -l')
         for line in std_out.readlines():
             if 'NOPASSWD' in line:
                 evar = list(line.strip().split()[1].split('=')[1])[10:14]
                 assert evar == list('0000')
         if exit_status != 0:
             journalctl_cmd = 'journalctl -x -n 100 --no-pager'
             multihost.master[0].run_command(journalctl_cmd)
             pytest.fail("%s cmd failed for user %s" % ('sudo -l', 'foo1'))
         ssh.close()
Beispiel #18
0
 def test_kvno_display(self, multihost, enable_kcm):
     """
     @Title: kcm: Test kvno correctly displays version numbers of principals
     #https://github.com/SSSD/sssd/issues/4763
     """
     ssh = SSHClient(multihost.master[0].sys_hostname,
                     username='******', password='******')
     host_princ = 'host/%s@%s' % (multihost.master[0].sys_hostname,
                                  'EXAMPLE.TEST')
     kvno_cmd = 'kvno %s' % (host_princ)
     (stdout, _, exit_status) = ssh.execute_cmd(kvno_cmd)
     for line in stdout.readlines():
         kvno_check = re.search(r'%s: kvno = (\d+)' % host_princ, line)
         if kvno_check:
             print(kvno_check.group())
         else:
             pytest.fail("kvno display was improper")
     ssh.close()
Beispiel #19
0
 def test_anonymous_pkinit_for_fast_false(self, multihost, backupsssdconf):
     """
     :title: Negative test for allow SSSD to use anonymous pkinit for FAST
     :id: de823122-af88-41f6-b762-63083fccaa87
     :customerscenario: True
     :description:
      For SSSD to use FAST a Kerberos keytab and service principal must
      exist. SSSD to be enhanced to allow for the use of anonymous pkinit
      to create the FAST session. With
      'krb5_fast_use_anonymous_pkinit = False' the ccache will have a
      ticket for the host principal.
     :steps:
       1. Setup a IPA server/client with default setting.
       2. Call anonymous processing using #kinit -n.
       3. Set 'krb5_fast_use_anonymous_pkinit = False' in sssd.conf.
       4. Login to the IPA user.
       5. Check a ccache file for the host principal.
     :expectedresults:
       1. Successfully setup the IPA server/client.
       2. Successfully called anonymous processing.
       3. Successfully set the option in sssd.conf.
       4. Successfully logged in to IPA user.
       5. Successfully get a ccache file with the host principal.
     :bugzilla:
     https://bugzilla.redhat.com/show_bug.cgi?id=1859751
     """
     sssd_client = sssdTools(multihost.client[0])
     domain_section = sssd_client.get_domain_section_name()
     domain_name = f'domain/{domain_section}'
     add_anony_pkinit = {'krb5_fast_use_anonymous_pkinit': 'False'}
     sssd_client.sssd_conf(domain_name, add_anony_pkinit)
     sssd_client.clear_sssd_cache()
     cmd_kinit = multihost.client[0].run_command('kinit -n')
     assert cmd_kinit.returncode == 0
     ssh = SSHClient(multihost.client[0].ip,
                     username='******',
                     password='******')
     ssh.close()
     cmd_klist = f'klist /var/lib/sss/db/fast_ccache_{domain_section.upper()}'
     output = multihost.client[0].run_command(cmd_klist).stdout_text
     principal = re.compile(
         rf'principal:.host.{multihost.client[0].sys_hostname}@{domain_section.upper()}'
     )
     assert principal.search(output)
Beispiel #20
0
 def test_offline_ssh_login(self, multihost):
     """@Title: Login: Verify offline ssh login"""
     multihost.master[0].transport.get_file('/etc/sssd/sssd.conf',
                                            '/tmp/sssd.conf')
     sssdconfig = ConfigParser.RawConfigParser()
     sssdconfig.read('/tmp/sssd.conf')
     domain_section = "%s/%s" % ('domain', 'EXAMPLE.TEST')
     if domain_section in sssdconfig.sections():
         sssdconfig.set(domain_section, 'cache_credentials', 'True')
         sssdconfig.set(domain_section, 'krb5_store_password_if_offline',
                        'True')
         sssdconfig.set('pam', 'offline_credentials_expiration', '0')
         with open('/tmp/sssd.conf', "w") as fd:
             sssdconfig.write(fd)
     else:
         print("Could not fetch sssd.conf")
         assert False
     multihost.master[0].transport.put_file('/tmp/sssd.conf',
                                            '/etc/sssd/sssd.conf')
     multihost.master[0].service_sssd('restart')
     time.sleep(5)
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Unable to authenticate as %s" % ('foo4'))
     else:
         ssh.close()
         stop_dirsrv = 'systemctl stop dirsrv@example1'
         stop_krb5kdc = 'systemctl stop krb5kdc'
         multihost.master[0].run_command(stop_dirsrv)
         multihost.master[0].run_command(stop_krb5kdc)
         try:
             ssh = SSHClient(multihost.master[0].sys_hostname,
                             username='******', password='******')
         except paramiko.ssh_exception.AuthenticationException:
             pytest.fail("Unable to authenticate as %s" % ('foo4'))
         else:
             ssh.close()
             start_dirsrv = 'systemctl start dirsrv@example1'
             start_krb5kdc = 'systemctl start krb5kdc'
             multihost.master[0].run_command(start_dirsrv)
             multihost.master[0].run_command(start_krb5kdc)
    def test_0021_ldapldap(self, multihost, multidomain_sssd):
        """
        @Title: IDM-SSSD-TC: ldap_provider: test_for_multidomain: User
        information not updated on login for secondary domains bz678593

        multidomain_sssd(domains='ldap_ldap')
        """
        multidomain_sssd(domains='ldap_ldap')
        ret = multihost.client[0].service_sssd('start')
        assert ret == 0
        suffix = ['p', 'q']
        for dom in range(2):
            for idx in range(5):
                user = '******' % (suffix[dom], idx, dom + 1)
                ssh = SSHClient(multihost.client[0].external_hostname,
                                username=user,
                                password='******')
                assert ssh.connect
                ssh.close()
Beispiel #22
0
 def test_0002_1736796(self, multihost, localusers):
     """
     :title: config: "default_domain_suffix" should not
      cause files domain entries to be qualified, this can break sudo access
     :id: 4b7bdeff-51ba-46ed-b8e1-0685515b87a0
     """
     users = localusers
     for user in users.keys():
         allow_sudo = '%s    ALL=(ALL) NOPASSWD:ALL' % user
         sudoers_file = '/etc/sudoers.d/%s' % user
         multihost.client[0].put_file_contents(sudoers_file, allow_sudo)
     tools = sssdTools(multihost.client[0])
     sssd_params = {'default_domain_suffix': 'foo',
                    'domains': 'LOCAL'}
     tools.sssd_conf('sssd', sssd_params)
     domain_section = 'domain/LOCAL'
     domain_params = {'id_provider': 'files'}
     tools.sssd_conf(domain_section, domain_params)
     multihost.client[0].service_sssd('restart')
     for user in users.keys():
         try:
             ssh = SSHClient(multihost.client[0].external_hostname,
                             username=user,
                             password='******')
         except paramiko.ssh_exception.AuthenticationException:
             pytest.fail("%s failed to login" % user)
         else:
             (stdout, _, exit_status) = ssh.execute_cmd('id')
             for line in stdout.readlines():
                 if '%s@implicit_files' % (user) in line:
                     pytest.fail("id command contains implicit_files")
             (_, _, exit_status) = ssh.execute_cmd('sudo su - -c id')
             assert exit_status == 0
         if exit_status != 0:
             journalctl_cmd = 'journalctl -x -n 100 --no-pager'
             multihost.client[0].run_command(journalctl_cmd)
             pytest.fail("%s cmd failed for user %s" % ('sudo su - -c id',
                                                        user))
         ssh.close()
     for user in users.keys():
         sudoers_file = '/etc/sudoers.d/%s' % user
         delete_file = 'rm -f %s' % sudoers_file
         multihost.client[0].run_command(delete_file)
Beispiel #23
0
 def test_refresh_expired_rule(self, multihost, enable_sss_sudo_nsswitch,
                               generic_sudorule,
                               set_entry_cache_sudo_timeout):
     """
     :title: sudo: Verify refreshing expired sudo rules
      do not crash sssd_sudo
     :id: 532513b2-15bc-46ac-8fc9-19fd0bf485c4
     """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("%s failed to login" % 'foo1')
     else:
         print("Executing %s command as %s user" % ('sudo -l', 'foo1'))
         (_, _, exit_status) = ssh.execute_cmd('sudo -l')
         assert exit_status == 0
         time.sleep(30)
         ssh.close()
Beispiel #24
0
 def test_kinit(self, multihost):
     """
     :title: Login: Verify kinit is successfull after user login
     :id: 5e15e9e9-c559-49b8-a164-abe13d82d0fd
     """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo2'))
     else:
         (_, _, exit_status) = ssh.execute_cmd(args='kinit',
                                               stdin='Secret123')
         assert exit_status == 0
         (stdout, _, _) = ssh.execute_cmd('klist')
         for line in stdout.readlines():
             print(line)
             assert exit_status == 0
             ssh.close()
Beispiel #25
0
 def test_kinit_kcm(self, multihost):
     """ Run kinit with KRB5CCNAME=KCM: """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo3'))
     else:
         (_, _, exit_status) = ssh.execute_cmd('KRB5CCNAME=KCM:; kinit',
                                               stdin='Secret123')
         assert exit_status == 0
         (stdout, _, _) = ssh.execute_cmd('KRB5CCNAME=KCM:;klist')
         for line in stdout.readlines():
             if 'Ticket cache: KCM:14583103' in str(line.strip()):
                 assert True
                 break
             else:
                 assert False
         assert exit_status == 0
         ssh.close()
Beispiel #26
0
    def _change_test_reset_password(self, multihost):
        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo1'))

        expect_script = chpass(multihost, ssh, 'Secret123', 'Secret1234')
        ssh.close()

        # Try logging in with the new password
        try:
            ssh = SSHClient(multihost.master[0].sys_hostname,
                            username='******', password='******')
        except paramiko.ssh_exception.AuthenticationException:
            pytest.fail("Authentication Failed as user %s" % ('foo1'))

        # Clean up and change the password back
        expect_script = chpass(multihost, ssh, 'Secret1234', 'Secret123')
        ssh.close()
Beispiel #27
0
 def test_kinit_kcm(self, multihost, enable_kcm):
     """ Run kinit with KRB5CCNAME=KCM: """
     self._start_kcm(multihost)
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******', password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("Authentication Failed as user %s" % ('foo3'))
     else:
         (_, _, exit_status) = ssh.execute_cmd('KRB5CCNAME=KCM:; kinit',
                                               stdin='Secret123')
         assert exit_status == 0
         (stdout, _, _) = ssh.execute_cmd('KRB5CCNAME=KCM:;klist')
         for line in stdout.readlines():
             if 'Ticket cache: KCM:14583103' in str(line.strip()):
                 assert True
                 break
             else:
                 assert False
         assert exit_status == 0
         ssh.close()
Beispiel #28
0
    def test_kcm_peruid_quota_increase(self,
                                       multihost,
                                       enable_kcm,
                                       create_many_user_principals):
        """
        @Title: kcm: Quota increase

        Increasing the peruid quota allows a client to store more
        data
        """
        # It is easier to keep these tests stable and independent from others
        # if they start from a clean slate
        self._remove_secret_db(multihost)

        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
                             username='******', password='******')

        # The loop would request 63 users, plus there is foo3 we authenticated
        # earlier, so this should exactly deplete the quota, but should succeed
        for i in range(1, 64):
            username = "******" % i
            (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username,
                                                       stdin='Secret123')
            assert exit_status == 0

        # this kinit should be exactly one over the peruid limit
        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
                                                   stdin='Secret123')
        assert exit_status != 0

        set_param(multihost, 'kcm', 'max_uid_ccaches', '65')
        self._restart_kcm(multihost)

        # Now the kinit should work as we increased the limit
        (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064',
                                                   stdin='Secret123')
        assert exit_status == 0

        ssh_foo3.execute_cmd('kdestroy -A')
        ssh_foo3.close()
 def test_server_access(self, multihost):
     """
     :title: Proxy server access
     :id: 5fe5839b-fbfb-48be-87de-18c1b0de209c
     :steps:
       1. Block server access
       2. User should not have access
       3. Unblock server access
       4. User should have access
     :expectedresults:
       1. Should succeed
       2. Should succeed
       3. Should succeed
       4. Should succeed
     """
     tools = sssdTools(multihost.client[0])
     client_e = multihost.client[0].ip
     tools.clear_sssd_cache()
     ssh1 = SSHClient(client_e,
                      username="******",
                      password="******")
     ssh1.close()
     # block_server_access
     execute_cmd(multihost, "systemctl start firewalld")
     execute_cmd(
         multihost, f"firewall-cmd --direct "
         f"--add-rule ipv4 filter "
         f"OUTPUT 0 -d {multihost.master[0].ip} "
         f"-j DROP")
     with pytest.raises(paramiko.ssh_exception.AuthenticationException):
         SSHClient(client_e, username="******", password="******")
     # unblock_server_access
     execute_cmd(multihost, "firewall-cmd  --reload")
     execute_cmd(multihost, "systemctl stop firewalld")
     tools.clear_sssd_cache()
     ssh1 = SSHClient(client_e,
                      username="******",
                      password="******")
     ssh1.close()
Beispiel #30
0
 def test_anonymous_pkinit_for_fast(self, multihost, backupsssdconf):
     """
     :title: Allow SSSD to use anonymous pkinit for FAST
     :id: 4a3ecc11-0d5b-4dce-bd08-5b1f47164b44
     :customerscenario: True
     :description:
      For SSSD to use FAST a Kerberos keytab and service principal must
      exist. SSSD to be enhanced to allow for the use of anonymous pkinit
      to create the FAST session.
     :steps:
       1. Setup a IPA server/client with default setting.
       2. Call anonymous processing using #kinit -n.
       3. Set 'krb5_fast_use_anonymous_pkinit = True' in sssd.conf.
       4. Login to the IPA user.
       5. Check a ccache file with the FAST armor ticket.
     :expectedresults:
       1. Successfully setup the IPA server/client.
       2. Successfully called anonymous processing.
       3. Successfully set the option in sssd.conf.
       4. Successfully logged in to IPA user.
       5. Successfully get a ccache file with the FAST armor ticket
     :bugzilla:
     https://bugzilla.redhat.com/show_bug.cgi?id=1859751
     """
     sssd_client = sssdTools(multihost.client[0])
     domain_name = f'domain/{sssd_client.get_domain_section_name()}'
     add_anony_pkinit = {'krb5_fast_use_anonymous_pkinit': 'True'}
     sssd_client.sssd_conf(domain_name, add_anony_pkinit)
     sssd_client.clear_sssd_cache()
     cmd_kinit = multihost.client[0].run_command('kinit -n')
     assert cmd_kinit.returncode == 0
     ssh = SSHClient(multihost.client[0].ip,
                     username='******',
                     password='******')
     ssh.close()
     cmd_klist = f'klist /var/lib/sss/db/fast_ccache_{sssd_client.get_domain_section_name().upper()}'
     output = multihost.client[0].run_command(cmd_klist).stdout_text
     principal = 'WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS'
     assert principal in output
Beispiel #31
0
 def test_0002_login(self, multihost):
     """
     @Title: failover: Verify users can login when the first
     ldap server is down
     """
     user = '******' % ds_instance_name
     stop_ds1 = 'systemctl stop dirsrv@example'
     cmd = multihost.master[0].run_command(stop_ds1, raiseonerr=False)
     assert cmd.returncode == 0
     tools = sssdTools(multihost.client[0])
     multihost.client[0].service_sssd('stop')
     tools.remove_sss_cache('/var/lib/sss/db')
     multihost.client[0].service_sssd('start')
     # login as user
     ssh = SSHClient(multihost.client[0].external_hostname,
                     username=user,
                     password='******')
     assert ssh.connect
     ssh.close()
     # start the first directory server
     start_ds1 = 'systemctl start dirsrv@example'
     cmd = multihost.master[0].run_command(start_ds1, raiseonerr=False)
     assert cmd.returncode == 0
Beispiel #32
0
 def test_0022_ldapldap(self, multihost, multidomain_sssd):
     """
     :title: IDM-SSSD-TC: ldap_provider: test_for_multidomain: User
      information not updated on login for secondary domains bz678593
     :id: df54756c-b141-4127-8e51-75ead63df10c
     """
     multidomain_sssd(domains='ldap_ldap')
     ret = multihost.client[0].service_sssd('start')
     assert ret == 0
     suffix = ['p', 'q']
     for dom in range(2):
         for idx in range(5):
             user = '******' % (suffix[dom], idx, dom + 1)
             ssh = SSHClient(multihost.client[0].external_hostname,
                             username=user,
                             password='******')
             assert ssh.connect
             ssh.close()
     pamlogfile = '/var/log/sssd/sssd_pam.log'
     find1 = re.compile(r'\[puser0\@ldap1\]')
     find2 = re.compile(r'\[quser0\@ldap2\]')
     log = multihost.client[0].get_file_contents(pamlogfile).decode('utf-8')
     assert find1.search(log) and find2.search(log)
Beispiel #33
0
 def test_0003_stopsecondds(self, multihost):
     """
     @Title: failover: Stop second ldap server and verify
     users are able to login from first ldap server
     """
     stop_ds2 = 'systemctl stop dirsrv@example'
     cmd = multihost.master[1].run_command(stop_ds2, raiseonerr=False)
     assert cmd.returncode == 0
     tools = sssdTools(multihost.client[0])
     multihost.client[0].service_sssd('stop')
     tools.remove_sss_cache('/var/lib/sss/db')
     multihost.client[0].service_sssd('start')
     user = '******' % ds_instance_name
     # login as user
     ssh = SSHClient(multihost.client[0].external_hostname,
                     username=user,
                     password='******')
     assert ssh.connect
     ssh.close()
     # start the first directory server
     start_ds1 = 'systemctl start dirsrv@example'
     cmd = multihost.master[0].run_command(start_ds1, raiseonerr=False)
     assert cmd.returncode == 0
 def test_proxy_lookup(self, multihost, backupsssdconf):
     """
     :title: Proxy lookup and kerberos auth
     :id: 5c4c55b8-0cac-47d0-aa23-d057b790e18e
     :steps:
       1. Check ldap user has access to client machine
       2. Proxy lookup and kerberos auth
     :expectedresults:
       1. Should succeed
       2. Should succeed
     """
     # proxy lookup and kerberos auth
     tools = sssdTools(multihost.client[0])
     client_e = multihost.client[0].ip
     tools.clear_sssd_cache()
     ssh1 = SSHClient(client_e,
                      username="******",
                      password="******")
     ssh1.close()
     assert "home/foo2:/bin/bash" in execute_cmd(
         multihost, "getent -s "
         "ldap passwd "
         "foo2").stdout_text
Beispiel #35
0
    def test_kcm_payload_low_quota(self,
                                   multihost,
                                   enable_kcm):
        """
        @Title: kcm: Quota enforcement

        Set a prohibitive quota for the per-ccache payload limit and
        make sure it gets enforced
        """
        # It is easier to keep these tests stable and independent from others
        # if they start from a clean slate
        self._remove_secret_db(multihost)

        ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
                             username='******', password='******')
        ssh_foo3.execute_cmd('kdestroy -A')
        ssh_foo3.close()

        set_param(multihost, 'kcm', 'max_ccache_size', '1')
        self._restart_kcm(multihost)

        with pytest.raises(paramiko.ssh_exception.AuthenticationException):
            ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
                                 username='******', password='******')
Beispiel #36
0
 def test_case_senitivity(self, multihost, case_sensitive_sudorule,
                          enable_sss_sudo_nsswitch,
                          set_case_sensitive_false):
     """
     :title: sudo: Verify case sensitivity in sudo responder
     :id: 64ab80be-17fd-4c3b-9d9b-7d07c6279975
     """
     try:
         ssh = SSHClient(multihost.master[0].sys_hostname,
                         username='******',
                         password='******')
     except paramiko.ssh_exception.AuthenticationException:
         pytest.fail("%s failed to login" % 'capsuser-1')
     else:
         (stdout, _, exit_status) = ssh.execute_cmd('sudo -l')
         result = []
         assert exit_status == 0
         for line in stdout.readlines():
             if 'NOPASSWD' in line:
                 line.strip()
                 result.append(line.strip('(root) NOPASSWD: '))
         assert '/usr/bin/less\n' in result
         assert '/usr/bin/more\n' in result
         ssh.close()
Beispiel #37
0
 def test_0010_bz1527662(self, multihost, adjoin):
     """
     :title: ad_parameters: Handle conflicting e-mail addresses
      more gracefully
     :id: 21b13b8f-0fc5-44e0-9ce0-e59f74826db0
     :customerscenario: True
     :steps:
       1. create ad user akhomic1 having mail akhomic1b@<domain>
       2. create ad user akhomic1b
       3. login as akhomic1 user
     :expectedresults:
       1. akhomic1 and akhomic1b should  successfully login
     """
     adjoin(membersw='adcli')
     user_list = ['akhomic1', 'akhomic1b']
     ad_realm = multihost.ad[0].domainname
     user_mail = 'akhomic1b@%s' % ad_realm
     client = sssdTools(multihost.client[0], multihost.ad[0])
     for user in user_list:
         group = '%s_group' % (user)
         client.create_ad_user(user, group, user_mail)
     multihost.client[0].service_sssd('restart')
     for user in user_list:
         ad_user = '******' % (user, ad_realm)
         try:
             ssh = SSHClient(multihost.client[0].sys_hostname,
                             username=ad_user,
                             password='******')
         except paramiko.ssh_exception.AuthenticationException:
             pytest.fail('%s failed to login' % user)
         else:
             ssh.close()
     for user in user_list:
         group = '%s_group' % (user)
         client.remove_ad_user_group(group)
         client.remove_ad_user_group(user)
Beispiel #38
0
 def test_authentication_indicators(self, multihost):
     """
     :title: Add support to verify authentication
      indicators in pam_sss_gss
     :bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1926622
     :id: 4891ed62-7fc8-11eb-98be-002b677efe14
     :steps:
         1. Add pam_sss_gss configuration to /etc/sssd/sssd.conf
         2. Add pam_sss_gss.so to /etc/pam.d/sudo
         3. Restart SSSD
         4. Enable SSSD debug logs
         5. Switch to 'admin' user
         6. obtain Kerberos ticket and check that it
            was obtained using SPAKE pre-authentication.
         7. Create sudo configuration that allows an admin to
            run SUDO rules
         8. Try 'sudo -l' as admin
         9. As root, check content of sssd_pam.log
        10. Check if acquired service ticket has req. indicators: 0
        11. Add pam_sss_gss configuration to /etc/sssd/sssd.conf
        12. Check if acquired service ticket has req.
            indicators: 2
     :expectedresults:
         1. Should succeed
         2. Should succeed
         3. Should succeed
         4. Should succeed
         5. Should succeed
         6. Should succeed
         7. Should succeed
         8. Should succeed
         9. Should succeed
        10. Should succeed
        11. Should succeed
        12. Should succeed
     """
     client = sssdTools(multihost.client[0])
     domain_params = {
         'pam_gssapi_services': 'sudo, sudo-i',
         'pam_gssapi_indicators_map': 'hardened, '
         'sudo:pkinit, '
         'sudo-i:otp'
     }
     client.sssd_conf('pam', domain_params)
     multihost.client[0].run_command('cp -vf '
                                     '/etc/pam.d/sudo '
                                     '/etc/pam.d/sudo_indicators')
     multihost.client[0].run_command("sed -i "
                                     "'2s/^/auth sufficient "
                                     "pam_sss_gss.so debug\\n/' "
                                     "/etc/pam.d/sudo")
     multihost.client[0].run_command('cp -vf '
                                     '/etc/pam.d/sudo-i '
                                     '/etc/pam.d/sudo-i_indicators')
     multihost.client[0].run_command("sed -i "
                                     "'2s/^/auth sufficient "
                                     "pam_sss_gss.so debug\\n/' "
                                     "/etc/pam.d/sudo-i")
     multihost.client[0].run_command('systemctl stop sssd ; '
                                     'rm -rf /var/log/sssd/* ; '
                                     'rm -rf /var/lib/sss/db/* ; '
                                     'systemctl start sssd')
     multihost.client[0].run_command("sssctl debug-level 9")
     ssh = SSHClient(multihost.client[0].ip,
                     username='******',
                     password='******')
     (_, _, exit_status) = ssh.execute_cmd('kinit admin', stdin='Secret123')
     (result, errors, exit_status) = ssh.exec_command('klist')
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudocmd-add ALL2')
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudorule-add '
                                                     'testrule2')
     (result, errors, exit_status) = ssh.execute_cmd("ipa sudorule-add"
                                                     "-allow-command "
                                                     "testrule2 "
                                                     "--sudocmds 'ALL2'")
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudorule-mod '
                                                     'testrule2 '
                                                     '--hostcat=all')
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudorule-add-user '
                                                     'testrule2 '
                                                     '--users admin')
     (result, errors, exit_status) = ssh.execute_cmd('sudo -l')
     ssh.close()
     search = multihost.client[0].run_command('fgrep '
                                              'gssapi_ '
                                              '/var/log/sssd/sssd_pam.log '
                                              '|tail -10')
     assert 'indicators: 0' in search.stdout_text
     client = sssdTools(multihost.client[0])
     domain_params = {
         'pam_gssapi_services': 'sudo, sudo-i',
         'pam_gssapi_indicators_map': 'sudo-i:hardened'
     }
     client.sssd_conf('pam', domain_params)
     multihost.client[0].run_command('systemctl stop sssd ; '
                                     'rm -rf /var/log/sssd/* ; '
                                     'rm -rf /var/lib/sss/db/* ; '
                                     'systemctl start sssd')
     ssh = SSHClient(multihost.client[0].ip,
                     username='******',
                     password='******')
     (_, _, exit_status) = ssh.execute_cmd('kinit admin', stdin='Secret123')
     multihost.client[0].run_command("sssctl debug-level 9")
     (result, errors, exit_status) = ssh.execute_cmd('sudo -l')
     (result, errors, exit_status) = ssh.exec_command('klist')
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudocmd-del ALL2')
     (result, errors, exit_status) = ssh.execute_cmd('ipa '
                                                     'sudorule-del '
                                                     'testrule2')
     multihost.client[0].run_command('cp -vf /etc/pam.d/sudo_indicators '
                                     '/etc/pam.d/sudo')
     multihost.client[0].run_command('cp -vf /etc/pam.d/sudo-i_indicators '
                                     '/etc/pam.d/sudo-i')
     search = multihost.client[0].run_command('fgrep gssapi_ '
                                              '/var/log/sssd/sssd_pam.log'
                                              ' |tail -10')
     ssh.close()
     assert 'indicators: 2' in search.stdout_text
Beispiel #39
0
 def test_inactivated_filtered_roles(self, multihost):
     """
     title: Inactivated filtered roles
     :id: 4286dac6-3045-11ec-8fd0-845cf3eff344
     :steps:
         1. Make filter role inactive
         2. User added to the above inactive filtered role
         3. User removed from the above inactive filtered role
         4. Activate filtered role
     :expectedresults:
         1. Should succeed
         2. Should succeed
         3. Should succeed
         4. Should succeed
     """
     clean_sys(multihost)
     client_e = multihost.client[0].ip
     master_e = multihost.master[0].ip
     ldap_uri = f'ldap://{master_e}'
     ds_rootdn = 'cn=Directory Manager'
     ds_rootpw = 'Secret123'
     ldap_inst = LdapOperations(ldap_uri, ds_rootdn, ds_rootpw)
     user_dn = 'uid=foo3,ou=People,dc=example,dc=test'
     role_dn = "filtered"
     add_member = [(ldap.MOD_ADD, 'o', role_dn.encode('utf-8'))]
     (ret, _) = ldap_inst.modify_ldap(user_dn, add_member)
     assert ret == 'Success'
     manage_user_roles(multihost, "cn=filtered", "lock", "role")
     with pytest.raises(paramiko.ssh_exception.AuthenticationException):
         SSHClient(client_e, username="******", password="******")
     time.sleep(3)
     lock_check(multihost, "foo3")
     # User added to the above inactive filtered role
     clean_sys(multihost)
     with pytest.raises(paramiko.ssh_exception.AuthenticationException):
         SSHClient(client_e, username="******", password="******")
     time.sleep(3)
     lock_check(multihost, "foo4")
     # User removed from the above inactive filtered role
     clean_sys(multihost)
     ldap_inst = LdapOperations(ldap_uri, ds_rootdn, ds_rootpw)
     user_dn = 'uid=foo3,ou=People,dc=example,dc=test'
     role_dn = "filtered"
     add_member = [(ldap.MOD_DELETE, 'o', role_dn.encode('utf-8'))]
     (ret, _) = ldap_inst.modify_ldap(user_dn, add_member)
     assert ret == 'Success'
     ssh1 = SSHClient(client_e,
                      username="******",
                      password="******")
     ssh1.close()
     time.sleep(3)
     unlock_check(multihost, "foo3")
     # Activate filtered role
     clean_sys(multihost)
     manage_user_roles(multihost, "cn=filtered", "unlock", "role")
     ssh1 = SSHClient(client_e,
                      username="******",
                      password="******")
     ssh1.close()
     time.sleep(3)
     unlock_check(multihost, "foo4")