mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-08 20:03:34 +02:00
Fprintd is dependent on the deprecated dbus-glib, also this doesn't provide various features we can take advantage of, like the ones for async authentication mechanism. So, remove all the dbus-glib dependencies and simplify the code, but without any further refactor, and keeping everything as it used to work, while this will give room for further improvements in subsequent commits. Internally, we just use dbus-codegen to generate the skeletons, and we use the generated FprintdDBusManager with composition, while we implement the device skeleton interface in FprintDevice, so that we don't have to use it as a proxy, and keep being closer to what it used to be with dbus-glib. Fixes: #61
207 lines
7.9 KiB
Python
Executable File
207 lines
7.9 KiB
Python
Executable File
#!/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 dbusmock
|
|
import fcntl
|
|
import os
|
|
import time
|
|
import pypamtest
|
|
|
|
PAM_SUCCESS = 0
|
|
PAM_AUTH_ERR = 7
|
|
PAM_AUTHINFO_UNAVAIL = 9
|
|
PAM_USER_UNKNOWN = 10
|
|
PAM_MAXTRIES = 11
|
|
|
|
class TestPamFprintd(dbusmock.DBusTestCase):
|
|
'''Test pam_fprintd'''
|
|
|
|
@classmethod
|
|
def start_monitor(klass):
|
|
'''Start dbus-monitor'''
|
|
|
|
workdir = os.environ['TOPBUILDDIR'] + '/tests/pam/'
|
|
klass.monitor_log = open(os.path.join(workdir, 'dbus-monitor.log'), 'wb', buffering=0)
|
|
klass.monitor = subprocess.Popen(['dbus-monitor', '--monitor', '--system'],
|
|
stdout=klass.monitor_log,
|
|
stderr=subprocess.STDOUT)
|
|
|
|
@classmethod
|
|
def stop_monitor(klass):
|
|
'''Stop dbus-monitor'''
|
|
|
|
assert klass.monitor
|
|
klass.monitor.terminate()
|
|
klass.monitor.wait()
|
|
|
|
klass.monitor_log.flush()
|
|
klass.monitor_log.close()
|
|
|
|
@classmethod
|
|
def setUpClass(klass):
|
|
klass.start_system_bus()
|
|
klass.start_monitor()
|
|
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)
|
|
|
|
@classmethod
|
|
def tearDownClass(klass):
|
|
klass.stop_monitor()
|
|
|
|
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_identify_error(self):
|
|
self.setup_device()
|
|
script = [
|
|
( 'verify-unknown-error', True, 2 )
|
|
]
|
|
self.device_mock.SetVerifyScript(script)
|
|
|
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
|
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_identify_error2(self):
|
|
self.setup_device()
|
|
script = [
|
|
( 'verify-disconnected', True, 2 )
|
|
]
|
|
self.device_mock.SetVerifyScript(script)
|
|
|
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
|
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_identify_error3(self):
|
|
self.setup_device()
|
|
script = [
|
|
( 'verify-INVALID', True, 2 )
|
|
]
|
|
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), 1)
|
|
self.assertRegex(res.errors[0], r'An unknown error occurred')
|
|
|
|
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_dual_reader_auth(self):
|
|
device_path = self.obj_fprintd_mock.AddDevice('FDO Sandpaper Reader', 3, 'press')
|
|
sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
|
|
sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger'])
|
|
script = [
|
|
( 'verify-match', True, 2 )
|
|
]
|
|
sandpaper_device_mock.SetVerifyScript(script)
|
|
|
|
# Add a 2nd device
|
|
self.setup_device()
|
|
|
|
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'Place your left middle finger on FDO Sandpaper Reader')
|
|
self.assertEqual(len(res.errors), 0)
|
|
|
|
def test_pam_fprintd_last_try_auth(self):
|
|
self.setup_device()
|
|
script = [
|
|
( 'verify-no-match', True, 1 ),
|
|
( 'verify-no-match', True, 1 ),
|
|
( 'verify-match', True, 1 ),
|
|
]
|
|
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), 2)
|
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
|
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
|
|
|
|
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_MAXTRIES)
|
|
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')
|
|
|
|
def test_pam_timeout(self):
|
|
self.setup_device()
|
|
|
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
|
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
|
self.assertRegex(res.info[1], r'Verification timed out')
|
|
|
|
if __name__ == '__main__':
|
|
if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
|
|
print('Cannot run test without environment set correctly, run "meson test" instead')
|
|
sys.exit(1)
|
|
# set stream to sys.stderr to get debug output
|
|
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
|