dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone
Blob Blame History Raw
From 0c56f4aee8115081cf0ee32cceb8c1dc56945e6f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 26 Sep 2018 11:48:37 +0200
Subject: [PATCH 42/47] intg: require SC tests

Integration test for the new try_cert_auth and require_cert_auth option
for pam_sss.

Related to https://pagure.io/SSSD/sssd/issue/3650

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
(cherry picked from commit 5cdb6968f407c7bcaba69f4892f51fd6426dddb2)
---
 src/tests/intg/Makefile.am           |  16 ++-
 src/tests/intg/test_pam_responder.py | 188 +++++++++++++++++++++++++++++++----
 2 files changed, 182 insertions(+), 22 deletions(-)

diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
index bb3a7f01ae4f79fa05cd661993e8f9872ecd0450..44fb6353ad031fc9edac291ce70aa7557999509d 100644
--- a/src/tests/intg/Makefile.am
+++ b/src/tests/intg/Makefile.am
@@ -113,6 +113,20 @@ pam_sss_service:
 	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
 	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
 
+pam_sss_sc_required:
+	$(MKDIR_P) $(PAM_SERVICE_DIR)
+	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so require_cert_auth retry=1"  > $(PAM_SERVICE_DIR)/$@
+	echo "account  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+
+pam_sss_try_sc:
+	$(MKDIR_P) $(PAM_SERVICE_DIR)
+	echo "auth     required       $(DESTDIR)$(pammoddir)/pam_sss.so try_cert_auth"  > $(PAM_SERVICE_DIR)/$@
+	echo "account  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+	echo "password required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+	echo "session  required       $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
+
 CLEANFILES=config.py config.pyc passwd group
 
 clean-local:
@@ -127,7 +141,7 @@ PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem"
 SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf"
 endif
 
-intgcheck-installed: config.py passwd group pam_sss_service
+intgcheck-installed: config.py passwd group pam_sss_service pam_sss_sc_required pam_sss_try_sc
 	pipepath="$(DESTDIR)$(pipepath)"; \
 	if test $${#pipepath} -gt 80; then \
 	    echo "error: Pipe directory path too long," \
diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
index c6d048cd342838fe312287eaffff734e30ba9e1c..06f69a3d82f5502fd5ae1928d81db0287e582e88 100644
--- a/src/tests/intg/test_pam_responder.py
+++ b/src/tests/intg/test_pam_responder.py
@@ -41,6 +41,11 @@ USER1 = dict(name='user1', passwd='x', uid=10001, gid=20001,
              dir='/home/user1',
              shell='/bin/bash')
 
+USER2 = dict(name='user2', passwd='x', uid=10002, gid=20002,
+             gecos='User with no Smartcard mapping',
+             dir='/home/user2',
+             shell='/bin/bash')
+
 
 def format_pam_cert_auth_conf(config):
     """Format a basic SSSD configuration"""
@@ -55,8 +60,11 @@ def format_pam_cert_auth_conf(config):
 
         [pam]
         pam_cert_auth = True
-        pam_p11_allowed_services = +pam_sss_service
+        pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \
+                                   +pam_sss_try_sc
         pam_cert_db_path = {config.PAM_CERT_DB_PATH}
+        p11_child_timeout = 5
+        p11_wait_for_card_timeout = 5
         debug_level = 10
 
         [domain/auth_only]
@@ -149,6 +157,15 @@ def create_nssdb():
     pkcs11_txt.close()
 
 
+def create_nssdb_no_cert():
+    os.mkdir(config.SYSCONFDIR + "/pki")
+    os.mkdir(config.SYSCONFDIR + "/pki/nssdb")
+    if subprocess.call(["certutil", "-N", "-d",
+                        "sql:" + config.SYSCONFDIR + "/pki/nssdb/",
+                        "--empty-password"]) != 0:
+        raise Exception("certutil failed")
+
+
 def cleanup_nssdb():
     shutil.rmtree(config.SYSCONFDIR + "/pki")
 
@@ -158,14 +175,42 @@ def create_nssdb_fixture(request):
     request.addfinalizer(cleanup_nssdb)
 
 
+def create_nssdb_no_cert_fixture(request):
+    create_nssdb_no_cert()
+    request.addfinalizer(cleanup_nssdb)
+
+
 @pytest.fixture
-def simple_pam_cert_auth(request):
+def simple_pam_cert_auth(request, passwd_ops_setup):
     """Setup SSSD with pam_cert_auth=True"""
     config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
     conf = format_pam_cert_auth_conf(config)
     create_conf_fixture(request, conf)
     create_sssd_fixture(request)
     create_nssdb_fixture(request)
+    passwd_ops_setup.useradd(**USER1)
+    passwd_ops_setup.useradd(**USER2)
+    return None
+
+
+@pytest.fixture
+def simple_pam_cert_auth_no_cert(request, passwd_ops_setup):
+    """Setup SSSD with pam_cert_auth=True"""
+    config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
+
+    old_softhsm2_conf = os.environ['SOFTHSM2_CONF']
+    del os.environ['SOFTHSM2_CONF']
+
+    conf = format_pam_cert_auth_conf(config)
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+    create_nssdb_no_cert_fixture(request)
+
+    os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf
+
+    passwd_ops_setup.useradd(**USER1)
+    passwd_ops_setup.useradd(**USER2)
+
     return None
 
 
@@ -176,26 +221,26 @@ def test_preauth_indicator(simple_pam_cert_auth):
 
 
 @pytest.fixture
-def pam_wrapper_setup(request):
+def env_for_sssctl(request):
     pwrap_runtimedir = os.getenv("PAM_WRAPPER_SERVICE_DIR")
     if pwrap_runtimedir is None:
         raise ValueError("The PAM_WRAPPER_SERVICE_DIR variable is unset\n")
 
+    env_for_sssctl = os.environ.copy()
+    env_for_sssctl['PAM_WRAPPER'] = "1"
+    env_for_sssctl['SSSD_INTG_PEER_UID'] = "0"
+    env_for_sssctl['SSSD_INTG_PEER_GID'] = "0"
+    env_for_sssctl['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
 
-def test_sc_auth_wrong_pin(simple_pam_cert_auth, pam_wrapper_setup,
-                           passwd_ops_setup):
+    return env_for_sssctl
 
-    passwd_ops_setup.useradd(**USER1)
-    current_env = os.environ.copy()
-    current_env['PAM_WRAPPER'] = "1"
-    current_env['SSSD_INTG_PEER_UID'] = "0"
-    current_env['SSSD_INTG_PEER_GID'] = "0"
-    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
+
+def test_sc_auth_wrong_pin(simple_pam_cert_auth, env_for_sssctl):
 
     sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
                                "--action=auth", "--service=pam_sss_service"],
                               universal_newlines=True,
-                              env=current_env, stdin=subprocess.PIPE,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
     try:
@@ -214,19 +259,120 @@ def test_sc_auth_wrong_pin(simple_pam_cert_auth, pam_wrapper_setup,
                     "Authentication failure") != -1
 
 
-def test_sc_auth(simple_pam_cert_auth, pam_wrapper_setup, passwd_ops_setup):
-
-    passwd_ops_setup.useradd(**USER1)
-    current_env = os.environ.copy()
-    current_env['PAM_WRAPPER'] = "1"
-    current_env['SSSD_INTG_PEER_UID'] = "0"
-    current_env['SSSD_INTG_PEER_GID'] = "0"
-    current_env['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
+def test_sc_auth(simple_pam_cert_auth, env_for_sssctl):
 
     sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
                                "--action=auth", "--service=pam_sss_service"],
                               universal_newlines=True,
-                              env=current_env, stdin=subprocess.PIPE,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+    try:
+        out, err = sssctl.communicate(input="123456")
+    except:
+        sssctl.kill()
+        out, err = sssctl.communicate()
+
+    sssctl.stdin.close()
+    sssctl.stdout.close()
+
+    if sssctl.wait() != 0:
+        raise Exception("sssctl failed")
+
+    assert err.find("pam_authenticate for user [user1]: Success") != -1
+
+
+def test_require_sc_auth(simple_pam_cert_auth, env_for_sssctl):
+
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
+                               "--action=auth",
+                               "--service=pam_sss_sc_required"],
+                              universal_newlines=True,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+    try:
+        out, err = sssctl.communicate(input="123456")
+    except:
+        sssctl.kill()
+        out, err = sssctl.communicate()
+
+    sssctl.stdin.close()
+    sssctl.stdout.close()
+
+    if sssctl.wait() != 0:
+        raise Exception("sssctl failed")
+
+    assert err.find("pam_authenticate for user [user1]: Success") != -1
+
+
+def test_require_sc_auth_no_cert(simple_pam_cert_auth_no_cert, env_for_sssctl):
+
+    # We have to wait about 20s before the command returns because there will
+    # be 2 run since retry=1 in the PAM configuration and both
+    # p11_child_timeout and p11_wait_for_card_timeout are 5s in sssd.conf,
+    # so 2*(5+5)=20. */
+    start_time = time.time()
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
+                               "--action=auth",
+                               "--service=pam_sss_sc_required"],
+                              universal_newlines=True,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+    try:
+        out, err = sssctl.communicate(input="123456")
+    except:
+        sssctl.kill()
+        out, err = sssctl.communicate()
+
+    sssctl.stdin.close()
+    sssctl.stdout.close()
+
+    if sssctl.wait() != 0:
+        raise Exception("sssctl failed")
+
+    end_time = time.time()
+    assert end_time > start_time and \
+        (end_time - start_time) >= 20 and \
+        (end_time - start_time) < 40
+    assert out.find("Please enter smart card\nPlease enter smart card") != -1
+    assert err.find("pam_authenticate for user [user1]: Authentication " +
+                    "service cannot retrieve authentication info") != -1
+
+
+def test_try_sc_auth_no_map(simple_pam_cert_auth, env_for_sssctl):
+
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user2",
+                               "--action=auth",
+                               "--service=pam_sss_try_sc"],
+                              universal_newlines=True,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
+                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+    try:
+        out, err = sssctl.communicate(input="123456")
+    except:
+        sssctl.kill()
+        out, err = sssctl.communicate()
+
+    sssctl.stdin.close()
+    sssctl.stdout.close()
+
+    if sssctl.wait() != 0:
+        raise Exception("sssctl failed")
+
+    assert err.find("pam_authenticate for user [user2]: Authentication " +
+                    "service cannot retrieve authentication info") != -1
+
+
+def test_try_sc_auth(simple_pam_cert_auth, env_for_sssctl):
+
+    sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
+                               "--action=auth",
+                               "--service=pam_sss_try_sc"],
+                              universal_newlines=True,
+                              env=env_for_sssctl, stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
     try:
-- 
2.14.4