Blame tests/pam/test_pam_fprintd.py

Packit Service 8ebd8e
#!/usr/bin/python3
Packit Service 8ebd8e
Packit Service 8ebd8e
# This program is free software; you can redistribute it and/or modify it under
Packit Service 8ebd8e
# the terms of the GNU Lesser General Public License as published by the Free
Packit Service 8ebd8e
# Software Foundation; either version 3 of the License, or (at your option) any
Packit Service 8ebd8e
# later version.  See http://www.gnu.org/copyleft/lgpl.html for the full text
Packit Service 8ebd8e
# of the license.
Packit Service 8ebd8e
Packit Service 8ebd8e
__author__ = 'Bastien Nocera'
Packit Service 8ebd8e
__email__ = 'hadess@hadess.net'
Packit Service 8ebd8e
__copyright__ = '(c) 2020 Red Hat Inc.'
Packit Service 8ebd8e
__license__ = 'LGPL 3+'
Packit Service 8ebd8e
Packit Service 8ebd8e
import tempfile
Packit Service 8ebd8e
import unittest
Packit Service 8ebd8e
import sys
Packit Service 8ebd8e
import subprocess
Packit Service 8ebd8e
import dbus
Packit Service 8ebd8e
import dbusmock
Packit Service 8ebd8e
import glob
Packit Service 8ebd8e
import os
Packit Service 8ebd8e
import shutil
Packit Service 8ebd8e
import time
Packit Service 8ebd8e
import pypamtest
Packit Service 8ebd8e
Packit Service 8ebd8e
PAM_SUCCESS = 0
Packit Service 8ebd8e
PAM_AUTH_ERR = 7
Packit Service 8ebd8e
PAM_AUTHINFO_UNAVAIL = 9
Packit Service 8ebd8e
PAM_USER_UNKNOWN = 10
Packit Service 8ebd8e
PAM_MAXTRIES = 11
Packit Service 8ebd8e
Packit Service 8ebd8e
class TestPamFprintd(dbusmock.DBusTestCase):
Packit Service 8ebd8e
    '''Test pam_fprintd'''
Packit Service 8ebd8e
Packit Service 8ebd8e
    @classmethod
Packit Service 8ebd8e
    def start_monitor(klass):
Packit Service 8ebd8e
        '''Start dbus-monitor'''
Packit Service 8ebd8e
Packit Service 8ebd8e
        workdir = os.environ['TOPBUILDDIR'] + '/tests/pam/'
Packit Service 8ebd8e
        klass.monitor_log = open(os.path.join(workdir, 'dbus-monitor.log'), 'wb', buffering=0)
Packit Service 8ebd8e
        klass.monitor = subprocess.Popen(['dbus-monitor', '--monitor', '--system'],
Packit Service 8ebd8e
                                         stdout=klass.monitor_log,
Packit Service 8ebd8e
                                         stderr=subprocess.STDOUT)
Packit Service 8ebd8e
Packit Service 8ebd8e
    @classmethod
Packit Service 8ebd8e
    def stop_monitor(klass):
Packit Service 8ebd8e
        '''Stop dbus-monitor'''
Packit Service 8ebd8e
Packit Service 8ebd8e
        assert klass.monitor
Packit Service 8ebd8e
        klass.monitor.terminate()
Packit Service 8ebd8e
        klass.monitor.wait()
Packit Service 8ebd8e
Packit Service 8ebd8e
        klass.monitor_log.flush()
Packit Service 8ebd8e
        klass.monitor_log.close()
Packit Service 8ebd8e
Packit Service 8ebd8e
    @classmethod
Packit Service 8ebd8e
    def setUpClass(klass):
Packit Service 8ebd8e
        klass.start_system_bus()
Packit Service 8ebd8e
        klass.start_monitor()
Packit Service 8ebd8e
        klass.dbus_con = klass.get_dbus(True)
Packit Service 8ebd8e
Packit Service 8ebd8e
        template_path = './'
Packit Service 8ebd8e
        if 'TOPSRCDIR' in os.environ:
Packit Service 8ebd8e
            template_path = os.environ['TOPSRCDIR'] + '/tests/'
Packit Service 8ebd8e
        klass.template_name = template_path + 'dbusmock/fprintd.py'
Packit Service 8ebd8e
        print ('Using template from %s' % klass.template_name)
Packit Service 8ebd8e
Packit Service 8ebd8e
    @classmethod
Packit Service 8ebd8e
    def tearDownClass(klass):
Packit Service 8ebd8e
        klass.stop_monitor()
Packit Service 8ebd8e
Packit Service 8ebd8e
        # Remove pam wrapper files, as they may break other tests
Packit Service 8ebd8e
        [shutil.rmtree(i) for i in glob.glob('/tmp/pam.[0-9A-z]')]
Packit Service 8ebd8e
Packit Service 8ebd8e
    def setUp(self):
Packit Service 8ebd8e
        (self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
Packit Service 8ebd8e
            self.template_name, {})
Packit Service 8ebd8e
        self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def tearDown(self):
Packit Service 8ebd8e
        self.p_mock.terminate()
Packit Service 8ebd8e
        self.p_mock.wait()
Packit Service 8ebd8e
Packit Service 8ebd8e
    def setup_device(self):
Packit Service 8ebd8e
        device_path = self.obj_fprintd_mock.AddDevice('FDO Trigger Finger Laser Reader', 3, 'swipe')
Packit Service 8ebd8e
        self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
Packit Service 8ebd8e
        self.device_mock.SetEnrolledFingers('toto', ['left-little-finger', 'right-little-finger'])
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_no_device(self):
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_identify_error(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-unknown-error', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_identify_error2(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-disconnected', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_identify_error3(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-INVALID', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTH_ERR)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 1)
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'An unknown error occurred')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_auth(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-match', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_no_fingers(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        self.device_mock.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s'))
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-match', True, 1 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_no_fingers_while_verifying(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'MOCK: no-prints', True, 1),
Packit Service 8ebd8e
            ( 'verify-match', True, 1 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_USER_UNKNOWN)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_blocks_unexpected_auth(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 3)
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_blocks_unexpected_auth2(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 3)
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_dual_reader_auth(self):
Packit Service 8ebd8e
        device_path = self.obj_fprintd_mock.AddDevice('FDO Sandpaper Reader', 3, 'press')
Packit Service 8ebd8e
        sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
Packit Service 8ebd8e
        sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger'])
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-match', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        sandpaper_device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        # Add a 2nd device
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Place your left middle finger on FDO Sandpaper Reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_last_try_auth(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-match', True, 1 ),
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 2)
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[1], r'Failed to match fingerprint')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_fprintd_failed_auth(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
            ( 'verify-no-match', True, 1 ),
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 3)
Packit Service 8ebd8e
        self.assertRegex(res.errors[0], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[1], r'Failed to match fingerprint')
Packit Service 8ebd8e
        self.assertRegex(res.errors[2], r'Failed to match fingerprint')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_already_claimed(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'verify-match', True, 2 )
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
        self.device_mock.SetClaimed('toto')
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
Packit Service 8ebd8e
        self.assertEqual(len(res.info), 0)
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_timeout(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
        self.assertRegex(res.info[1], r'Verification timed out')
Packit Service 8ebd8e
Packit Service 8ebd8e
    def test_pam_notices_fprintd_disappearing(self):
Packit Service 8ebd8e
        self.setup_device()
Packit Service 8ebd8e
Packit Service 8ebd8e
        script = [
Packit Service 8ebd8e
            ( 'MOCK: quit', True, 0 ),
Packit Service 8ebd8e
        ]
Packit Service 8ebd8e
        self.device_mock.SetVerifyScript(script)
Packit Service 8ebd8e
Packit Service 8ebd8e
        tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
Packit Service 8ebd8e
        res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
Packit Service 8ebd8e
        self.assertEqual(len(res.errors), 0)
Packit Service 8ebd8e
        self.assertEqual(len(res.info), 0)
Packit Service 8ebd8e
Packit Service 8ebd8e
if __name__ == '__main__':
Packit Service 8ebd8e
    if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
Packit Service 8ebd8e
        print('Cannot run test without environment set correctly, run "meson test" instead')
Packit Service 8ebd8e
        sys.exit(1)
Packit Service 8ebd8e
    # set stream to sys.stderr to get debug output
Packit Service 8ebd8e
    unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))