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