|
|
96eb28 |
From 612dda4bbd706be9e7c3674e4d0420f9ebd1ea83 Mon Sep 17 00:00:00 2001
|
|
|
96eb28 |
From: Jakub Hrozek <jhrozek@redhat.com>
|
|
|
96eb28 |
Date: Mon, 18 Jun 2018 09:12:13 +0200
|
|
|
96eb28 |
Subject: [PATCH] TESTS: Add a basic SSH responder test
|
|
|
96eb28 |
MIME-Version: 1.0
|
|
|
96eb28 |
Content-Type: text/plain; charset=UTF-8
|
|
|
96eb28 |
Content-Transfer-Encoding: 8bit
|
|
|
96eb28 |
|
|
|
96eb28 |
Adds a basic test that makes sure that a list of SSH public keys can be
|
|
|
96eb28 |
retrieved. This is to make sure we don't break the SSH integration later
|
|
|
96eb28 |
on.
|
|
|
96eb28 |
|
|
|
96eb28 |
Related:
|
|
|
96eb28 |
https://pagure.io/SSSD/sssd/issue/3747
|
|
|
96eb28 |
|
|
|
96eb28 |
Reviewed-by: Fabiano FidĂȘncio <fidencio@redhat.com>
|
|
|
96eb28 |
(cherry picked from commit 804c5b538ad89a1a3897b93f39d716fa50530842)
|
|
|
96eb28 |
---
|
|
|
96eb28 |
src/tests/intg/Makefile.am | 1 +
|
|
|
96eb28 |
src/tests/intg/test_ssh_pubkey.py | 232 ++++++++++++++++++++++++++++++++++++++
|
|
|
96eb28 |
2 files changed, 233 insertions(+)
|
|
|
96eb28 |
create mode 100644 src/tests/intg/test_ssh_pubkey.py
|
|
|
96eb28 |
|
|
|
96eb28 |
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
|
|
|
96eb28 |
index 209e5a0c73db99b11aa6967f30db23933d21acb0..285ce21f04dddb6388c595470eac8f31bc224a60 100644
|
|
|
96eb28 |
--- a/src/tests/intg/Makefile.am
|
|
|
96eb28 |
+++ b/src/tests/intg/Makefile.am
|
|
|
96eb28 |
@@ -35,6 +35,7 @@ dist_noinst_DATA = \
|
|
|
96eb28 |
data/ad_data.ldif \
|
|
|
96eb28 |
data/ad_schema.ldif \
|
|
|
96eb28 |
test_pysss_nss_idmap.py \
|
|
|
96eb28 |
+ test_ssh_pubkey.py \
|
|
|
96eb28 |
$(NULL)
|
|
|
96eb28 |
|
|
|
96eb28 |
config.py: config.py.m4
|
|
|
96eb28 |
diff --git a/src/tests/intg/test_ssh_pubkey.py b/src/tests/intg/test_ssh_pubkey.py
|
|
|
96eb28 |
new file mode 100644
|
|
|
96eb28 |
index 0000000000000000000000000000000000000000..fbf55566e341373873057ec4e3af1d7f83202aa7
|
|
|
96eb28 |
--- /dev/null
|
|
|
96eb28 |
+++ b/src/tests/intg/test_ssh_pubkey.py
|
|
|
96eb28 |
@@ -0,0 +1,232 @@
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+# ssh public key integration test
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+# Copyright (c) 2018 Red Hat, Inc.
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+# This is free software; you can redistribute it and/or modify it
|
|
|
96eb28 |
+# under the terms of the GNU General Public License as published by
|
|
|
96eb28 |
+# the Free Software Foundation; version 2 only
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+# This program is distributed in the hope that it will be useful, but
|
|
|
96eb28 |
+# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
96eb28 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
96eb28 |
+# General Public License for more details.
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+# You should have received a copy of the GNU General Public License
|
|
|
96eb28 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
96eb28 |
+#
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+import os
|
|
|
96eb28 |
+import stat
|
|
|
96eb28 |
+import signal
|
|
|
96eb28 |
+import subprocess
|
|
|
96eb28 |
+import time
|
|
|
96eb28 |
+import ldap
|
|
|
96eb28 |
+import ldap.modlist
|
|
|
96eb28 |
+import pytest
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+import config
|
|
|
96eb28 |
+import ds_openldap
|
|
|
96eb28 |
+import ent
|
|
|
96eb28 |
+import ldap_ent
|
|
|
96eb28 |
+from util import unindent, get_call_output
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+LDAP_BASE_DN = "dc=example,dc=com"
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+USER1_PUBKEY1 = "ssh-dss AAAAB3NzaC1kc3MAAACBAPMkvcU53RVhBtjwiC3IqeRIWR9Qwdv8\
|
|
|
96eb28 |
+DmZzEsDD3Csd6jYxMsPZoXcPrHqwYcEj1s5MVqhdSFS0Cjz13e7gO6OMLInO3xMBSSFHjfp9RE1H\
|
|
|
96eb28 |
+pgc4WisazzyJaW9EMkQo/DqvkFkKh31oqAmxcSbLAFJRg4TTIqm18qu8IRKS6m/RAAAAFQC97TA5\
|
|
|
96eb28 |
+JSsMsaX1bRszC7y4PhMBvQAAAIEAt9Yo9v/h9W4nDbzUdkGwNRszlPEK+T12bJv0O9Fk6subD3Do\
|
|
|
96eb28 |
+6A4Qru/Nr6voXoq8b018Wb7iFWvKOoz5uT/plWBKLXL2NN7ovTR+dUJIzvwurQZroukmU1EghNey\
|
|
|
96eb28 |
+lkSHmDlxSoMK6Nh21uGu6l+b6x5pXNaZHMpsywG4kY8SoC0AAACAAWLHneEGvqkYA8La4Eob+Hjj\
|
|
|
96eb28 |
+mAKilx8byxm3Kfb1XO+ZrR6XxadofZOaUYRMpPKgFjKAKPxJftPLiDjWM7lSe6h8df0dUMLVXt6m\
|
|
|
96eb28 |
+eA83kE0uK5JOOGJfJDqmRed2YnfxUDNNFQGT4xFWGrNtYNbGyw9BWKbkooAsLqaO04zP3Rs= \
|
|
|
96eb28 |
+user1@LDAP"
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+USER1_PUBKEY2 = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwHUUF3HPH+DkU6j8k7Q1wHG\
|
|
|
96eb28 |
+RJY9NeLqSav3h95mTSCQYPSC7I9RTJ4OORgqCbEzrP/DYrrn4TtQ9dhRJar3ZY+F36SH5yFIXORb\
|
|
|
96eb28 |
+lAIbFU+/anahBuFS9vHi1MqFPckGmwJ4QCpjQhdYxo1ro0e1RuGSaQNp/w9N6S/fDz4Cj4I99xDz\
|
|
|
96eb28 |
+SeQeGHxYv0e60plQ8dUajmnaGmYRJHF9a6Ban7IWySActCja7eQP2zIRXEZMpuhl1E0U4y+gHTFI\
|
|
|
96eb28 |
+gD3zQai3QrXm8RUrQURIJ0u6BlGS910OPbHqLpLTFWG08L8sNUcYzC+DY6yoCSO0n/Df3pVRS4C9\
|
|
|
96eb28 |
+5Krf3FqppMTjdfQ== user1@LDAP"
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+@pytest.fixture(scope="module")
|
|
|
96eb28 |
+def ds_inst(request):
|
|
|
96eb28 |
+ """LDAP server instance fixture"""
|
|
|
96eb28 |
+ ds_inst = ds_openldap.DSOpenLDAP(
|
|
|
96eb28 |
+ config.PREFIX, 10389, LDAP_BASE_DN,
|
|
|
96eb28 |
+ "cn=admin", "Secret123"
|
|
|
96eb28 |
+ )
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ try:
|
|
|
96eb28 |
+ ds_inst.setup()
|
|
|
96eb28 |
+ except:
|
|
|
96eb28 |
+ ds_inst.teardown()
|
|
|
96eb28 |
+ raise
|
|
|
96eb28 |
+ request.addfinalizer(ds_inst.teardown)
|
|
|
96eb28 |
+ return ds_inst
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+@pytest.fixture(scope="module")
|
|
|
96eb28 |
+def ldap_conn(request, ds_inst):
|
|
|
96eb28 |
+ """LDAP server connection fixture"""
|
|
|
96eb28 |
+ ldap_conn = ds_inst.bind()
|
|
|
96eb28 |
+ ldap_conn.ds_inst = ds_inst
|
|
|
96eb28 |
+ request.addfinalizer(ldap_conn.unbind_s)
|
|
|
96eb28 |
+ return ldap_conn
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_ldap_entries(ldap_conn, ent_list=None):
|
|
|
96eb28 |
+ """Add LDAP entries from ent_list"""
|
|
|
96eb28 |
+ if ent_list is not None:
|
|
|
96eb28 |
+ for entry in ent_list:
|
|
|
96eb28 |
+ ldap_conn.add_s(entry[0], entry[1])
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def cleanup_ldap_entries(ldap_conn, ent_list=None):
|
|
|
96eb28 |
+ """Remove LDAP entries added by create_ldap_entries"""
|
|
|
96eb28 |
+ if ent_list is None:
|
|
|
96eb28 |
+ for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
|
|
|
96eb28 |
+ for entry in ldap_conn.search_s("ou=" + ou + "," +
|
|
|
96eb28 |
+ ldap_conn.ds_inst.base_dn,
|
|
|
96eb28 |
+ ldap.SCOPE_ONELEVEL,
|
|
|
96eb28 |
+ attrlist=[]):
|
|
|
96eb28 |
+ ldap_conn.delete_s(entry[0])
|
|
|
96eb28 |
+ else:
|
|
|
96eb28 |
+ for entry in ent_list:
|
|
|
96eb28 |
+ ldap_conn.delete_s(entry[0])
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_ldap_cleanup(request, ldap_conn, ent_list=None):
|
|
|
96eb28 |
+ """Add teardown for removing all user/group LDAP entries"""
|
|
|
96eb28 |
+ request.addfinalizer(lambda: cleanup_ldap_entries(ldap_conn, ent_list))
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_ldap_fixture(request, ldap_conn, ent_list=None):
|
|
|
96eb28 |
+ """Add LDAP entries and add teardown for removing them"""
|
|
|
96eb28 |
+ create_ldap_entries(ldap_conn, ent_list)
|
|
|
96eb28 |
+ create_ldap_cleanup(request, ldap_conn, ent_list)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+SCHEMA_RFC2307_BIS = "rfc2307bis"
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def format_basic_conf(ldap_conn, schema):
|
|
|
96eb28 |
+ """Format a basic SSSD configuration"""
|
|
|
96eb28 |
+ schema_conf = "ldap_schema = " + schema + "\n"
|
|
|
96eb28 |
+ schema_conf += "ldap_group_object_class = groupOfNames\n"
|
|
|
96eb28 |
+ return unindent("""\
|
|
|
96eb28 |
+ [sssd]
|
|
|
96eb28 |
+ domains = LDAP
|
|
|
96eb28 |
+ services = nss, ssh
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ [nss]
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ [ssh]
|
|
|
96eb28 |
+ debug_level=10
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ [domain/LDAP]
|
|
|
96eb28 |
+ {schema_conf}
|
|
|
96eb28 |
+ id_provider = ldap
|
|
|
96eb28 |
+ auth_provider = ldap
|
|
|
96eb28 |
+ ldap_uri = {ldap_conn.ds_inst.ldap_url}
|
|
|
96eb28 |
+ ldap_search_base = {ldap_conn.ds_inst.base_dn}
|
|
|
96eb28 |
+ ldap_sudo_use_host_filter = false
|
|
|
96eb28 |
+ debug_level=10
|
|
|
96eb28 |
+ """).format(**locals())
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_conf_file(contents):
|
|
|
96eb28 |
+ """Create sssd.conf with specified contents"""
|
|
|
96eb28 |
+ conf = open(config.CONF_PATH, "w")
|
|
|
96eb28 |
+ conf.write(contents)
|
|
|
96eb28 |
+ conf.close()
|
|
|
96eb28 |
+ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def cleanup_conf_file():
|
|
|
96eb28 |
+ """Remove sssd.conf, if it exists"""
|
|
|
96eb28 |
+ if os.path.lexists(config.CONF_PATH):
|
|
|
96eb28 |
+ os.unlink(config.CONF_PATH)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_conf_cleanup(request):
|
|
|
96eb28 |
+ """Add teardown for removing sssd.conf"""
|
|
|
96eb28 |
+ request.addfinalizer(cleanup_conf_file)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_conf_fixture(request, contents):
|
|
|
96eb28 |
+ """
|
|
|
96eb28 |
+ Create sssd.conf with specified contents and add teardown for removing it
|
|
|
96eb28 |
+ """
|
|
|
96eb28 |
+ create_conf_file(contents)
|
|
|
96eb28 |
+ create_conf_cleanup(request)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_sssd_process():
|
|
|
96eb28 |
+ """Start the SSSD process"""
|
|
|
96eb28 |
+ if subprocess.call(["sssd", "-D", "-f"]) != 0:
|
|
|
96eb28 |
+ raise Exception("sssd start failed")
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def get_sssd_pid():
|
|
|
96eb28 |
+ pid_file = open(config.PIDFILE_PATH, "r")
|
|
|
96eb28 |
+ pid = int(pid_file.read())
|
|
|
96eb28 |
+ return pid
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def cleanup_sssd_process():
|
|
|
96eb28 |
+ """Stop the SSSD process and remove its state"""
|
|
|
96eb28 |
+ try:
|
|
|
96eb28 |
+ pid = get_sssd_pid()
|
|
|
96eb28 |
+ os.kill(pid, signal.SIGTERM)
|
|
|
96eb28 |
+ while True:
|
|
|
96eb28 |
+ try:
|
|
|
96eb28 |
+ os.kill(pid, signal.SIGCONT)
|
|
|
96eb28 |
+ except:
|
|
|
96eb28 |
+ break
|
|
|
96eb28 |
+ time.sleep(1)
|
|
|
96eb28 |
+ except:
|
|
|
96eb28 |
+ pass
|
|
|
96eb28 |
+ for path in os.listdir(config.DB_PATH):
|
|
|
96eb28 |
+ os.unlink(config.DB_PATH + "/" + path)
|
|
|
96eb28 |
+ for path in os.listdir(config.MCACHE_PATH):
|
|
|
96eb28 |
+ os.unlink(config.MCACHE_PATH + "/" + path)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_sssd_fixture(request):
|
|
|
96eb28 |
+ """Start SSSD and add teardown for stopping it and removing its state"""
|
|
|
96eb28 |
+ create_sssd_process()
|
|
|
96eb28 |
+ create_sssd_cleanup(request)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def create_sssd_cleanup(request):
|
|
|
96eb28 |
+ """Add teardown for stopping SSSD and removing its state"""
|
|
|
96eb28 |
+ request.addfinalizer(cleanup_sssd_process)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+@pytest.fixture
|
|
|
96eb28 |
+def add_user_with_ssh_key(request, ldap_conn):
|
|
|
96eb28 |
+ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
|
|
|
96eb28 |
+ ent_list.add_user("user1", 1001, 2001,
|
|
|
96eb28 |
+ sshPubKey=(USER1_PUBKEY1, USER1_PUBKEY2))
|
|
|
96eb28 |
+ ent_list.add_user("user2", 1002, 2001)
|
|
|
96eb28 |
+ create_ldap_fixture(request, ldap_conn, ent_list)
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
|
|
|
96eb28 |
+ create_conf_fixture(request, conf)
|
|
|
96eb28 |
+ create_sssd_fixture(request)
|
|
|
96eb28 |
+ return None
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+def test_ssh_pubkey_retrieve(add_user_with_ssh_key):
|
|
|
96eb28 |
+ """
|
|
|
96eb28 |
+ Test that we can retrieve an SSH public key for a user who has one
|
|
|
96eb28 |
+ and can't retrieve a key for a user who does not have one.
|
|
|
96eb28 |
+ """
|
|
|
96eb28 |
+ sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user1"])
|
|
|
96eb28 |
+ assert sshpubkey == USER1_PUBKEY1 + '\n' + USER1_PUBKEY2 + '\n'
|
|
|
96eb28 |
+
|
|
|
96eb28 |
+ sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user2"])
|
|
|
96eb28 |
+ assert len(sshpubkey) == 0
|
|
|
96eb28 |
--
|
|
|
96eb28 |
2.14.4
|
|
|
96eb28 |
|