tests: Add test for the PAM module

Test the PAM module using pam_wrapper and our mock fprintd.

See https://lwn.net/Articles/671094/

Note that this requires a version of pam_wrapper with this bug fixed:
https://bugzilla.samba.org/show_bug.cgi?id=14245
This commit is contained in:
Bastien Nocera 2020-01-20 17:34:45 +01:00
parent f1517af09a
commit 00b79d1a2f
7 changed files with 119 additions and 1 deletions

View file

@ -3,7 +3,7 @@ image: fedora:rawhide
variables:
DEPENDENCIES: dbus-glib-devel pam-devel polkit-devel
gtk-doc meson intltool autoconf automake libtool
gcc gcc-c++ glibc-devel make python3-dbusmock
gcc gcc-c++ glibc-devel make python3-dbusmock python3-libpamtest
DEPENDENCIES_STABLE: $DEPENDENCIES libfprint-devel
DEPENDENCIES_DEV: $DEPENDENCIES git
# Sync'ed up with https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/.gitlab-ci.yml

View file

@ -91,5 +91,7 @@ doc/Makefile
doc/version.xml
doc/dbus/Makefile
tests/Makefile
tests/pam/Makefile
tests/pam/services/Makefile
po/Makefile.in
])

View file

@ -1,3 +1,5 @@
SUBDIRS = pam
TESTS_ENVIRONMENT = export FPRINT_BUILD_DIR=$(abs_top_builddir)/src; export TOPSRCDIR=$(abs_top_srcdir); export PYTHON=@PYTHON@;
TESTS = fprintd.py test_fprintd_utils.py

6
tests/pam/Makefile.am Normal file
View file

@ -0,0 +1,6 @@
SUBDIRS = services
TESTS_ENVIRONMENT = export TOPSRCDIR=$(abs_top_srcdir); export LD_PRELOAD=libpam_wrapper.so; export PAM_WRAPPER_SERVICE_DIR=$(abs_top_builddir)/tests/pam/services; export PAM_WRAPPER=1; export PYTHON=@PYTHON@;
TESTS = test_pam_fprintd.py
EXTRA_DIST = $(TESTS)

View file

@ -0,0 +1,7 @@
all-am: fprintd-pam-test
fprintd-pam-test: fprintd-pam-test.in Makefile
sed -e "s|\@TOPBUILDDIR\@|$(abs_top_builddir)|" $< > $@
EXTRA_DIST = fprintd-pam-test.in
CLEANFILES = fprintd-pam-test

View file

@ -0,0 +1 @@
auth required @TOPBUILDDIR@/pam/.libs/pam_fprintd.so debug

100
tests/pam/test_pam_fprintd.py Executable file
View file

@ -0,0 +1,100 @@
#!/usr/bin/python3
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option) any
# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
# of the license.
__author__ = 'Bastien Nocera'
__email__ = 'hadess@hadess.net'
__copyright__ = '(c) 2020 Red Hat Inc.'
__license__ = 'LGPL 3+'
import tempfile
import unittest
import sys
import subprocess
import dbus
import dbus.mainloop.glib
import dbusmock
import fcntl
import os
import time
import pypamtest
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
PAM_SUCCESS = 0
PAM_AUTH_ERR = 7
PAM_AUTHINFO_UNAVAIL = 9
PAM_USER_UNKNOWN = 10
class TestPamFprintd(dbusmock.DBusTestCase):
'''Test pam_fprintd'''
@classmethod
def setUpClass(klass):
klass.start_system_bus()
klass.dbus_con = klass.get_dbus(True)
template_path = './'
if 'TOPSRCDIR' in os.environ:
template_path = os.environ['TOPSRCDIR'] + '/tests/'
klass.template_name = template_path + 'dbusmock/fprintd.py'
print ('Using template from %s' % klass.template_name)
def setUp(self):
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
self.template_name, {}, stdout=subprocess.PIPE)
# set log to nonblocking
flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
def tearDown(self):
self.p_mock.terminate()
self.p_mock.wait()
def setup_device(self):
device_path = self.obj_fprintd_mock.AddDevice('FDO Trigger Finger Laser Reader', 3, 'swipe')
self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
self.device_mock.SetEnrolledFingers('toto', ['left-little-finger', 'right-little-finger'])
def test_pam_fprintd_auth(self):
self.setup_device()
script = [
( 'verify-match', True, 2 )
]
self.device_mock.SetVerifyScript(script)
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
self.assertEqual(len(res.errors), 0)
def test_pam_fprintd_failed_auth(self):
self.setup_device()
script = [
( 'verify-no-match', True, 1 ),
( 'verify-no-match', True, 1 ),
( 'verify-no-match', True, 1 ),
]
self.device_mock.SetVerifyScript(script)
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTH_ERR)
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
self.assertEqual(len(res.errors), 3)
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
self.assertRegex(res.errors[2], r'Failed to match fingerprint')
if __name__ == '__main__':
if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
print('Cannot run test without environment set correctly, run "make check" instead')
sys.exit(1)
# set stream to sys.stderr to get debug output
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))