Skip to content

Commit

Permalink
Tests: Add following test cases for passkey with LDAP and IPA
Browse files Browse the repository at this point in the history
1. Register a key with sssctl
2. Register a key with IPA sssctl command
3. Check authentication of user with IPA and LDAP
4. Check auth deny when wrong pin is used to auth the user
   with IPA and LDAP
5. Check auth deny when wrong passkey mapping is used while
   adding user in IPA and LDAP.
6. Check authentication from cache when server is not reachable
7. Check auth deny when IPA and LDAP server is offline and cache is deleted

All tests cases automated with umockdev.

Signed-off-by: Madhuri Upadhye <[email protected]>
  • Loading branch information
madhuriupadhye committed Apr 6, 2023
1 parent 3d0fcca commit 9bdbcdf
Show file tree
Hide file tree
Showing 32 changed files with 2,695 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/tests/system/lib/sssd/roles/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def __init__(self, *args, **kwargs) -> None:
Standard tools interface.
"""

self.auth: AuthenticationUtils = AuthenticationUtils(self.host)
self.auth: AuthenticationUtils = AuthenticationUtils(self.host, self.fs)
"""
Authentication helpers.
"""
Expand Down
24 changes: 24 additions & 0 deletions src/tests/system/lib/sssd/roles/ipa.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,30 @@ def modify(
self._modify(attrs, input=password)
return self

def passkey_add(self, passkey_mapping: str | str = str ) -> IPAUser:
"""
Add passkey mapping
:param passkey_mapping: passkey string containing the credentialID,publicKey
:type passkey_mapping: str
:return: Self.
:rtype: IPAUser
"""
self._exec('add-passkey', [passkey_mapping])
return self

def passkey_remove(self, passkey_mapping: str | str = str) -> IPAUser:
"""
Remove passkey mapping.
:param passkey_mapping: passkey string containing the credentialID,publicKey
:type passkey_mapping: str
:return: Self.
:rtype: IPAUser.
"""
self._exec('remove-passkey', input=passkey_mapping)
return self


class IPAGroup(IPAObject):
"""
Expand Down
26 changes: 26 additions & 0 deletions src/tests/system/lib/sssd/roles/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,32 @@ def modify(
self._set(attrs)
return self

def passkey_add(self, passkey_mapping: str | str = str) -> LDAPUser:
"""
Add passkey mapping
:param passkey_mapping: passkey string containing the credentialID,publicKey
:type passkey_mapping: str
:return: Self.
:rtype: LDAPUser
"""
attrs: LDAPRecordAttributes = {"objectClass": "passkeyUser", "passkey": passkey_mapping}
self._modify(add=attrs)
return self

def passkey_remove(self, passkey_mapping: str | str = str) -> LDAPUser:
"""
Remove passkey mapping
:param passkey_mapping: passkey string containing the credentialID,publicKey
:type passkey_mapping: str
:return: Self.
:rtype: LDAPUser
"""
attrs: LDAPRecordAttributes = {"objectClass": "passkeyUser", "passkey": passkey_mapping}
self._modify(delete=attrs)
return self


class LDAPGroup(LDAPObject[LDAPHost, LDAP]):
"""
Expand Down
130 changes: 129 additions & 1 deletion src/tests/system/lib/sssd/utils/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@

from pytest_mh import MultihostHost, MultihostUtility
from pytest_mh.ssh import SSHClient, SSHProcessResult
from pytest_mh.utils.fs import LinuxFileSystem


__all__ = [
"AuthenticationUtils",
"KerberosAuthenticationUtils",
"SSHAuthenticationUtils",
"SUAuthenticationUtils",
"SudoAuthenticationUtils",
"PasskeyAuthenticationUtils",
]


Expand Down Expand Up @@ -43,12 +46,34 @@ def test_example(client: Client, provider: GenericProvider, method: str):
assert client.auth.parametrize(method).password('tuser', 'Secret123')
"""

def __init__(self, host: MultihostHost) -> None:
def __init__(self, host: MultihostHost, fs: LinuxFileSystem) -> None:
"""
:param host: Remote host.
:type host: MultihostHost
"""
super().__init__(host)
self.fs: LinuxFileSystem = fs

self.passkey: PasskeyAuthenticationUtils = PasskeyAuthenticationUtils(host, fs)
"""
Test passkey registration and passkey authentication with umockdev-run.
.. code-block:: python
:caption: Example usage
@pytest.mark.topology(KnownTopology.IPA)
def test_example(client: Client, ipa: IPA):
user = ipa.user('user1').add()
passkey_str = "passkey:NUZMRUXIb/W8Ij1GqwCDHSCWxt/SxWxckwtQjLYi/X6Y1qZFB+HI8WO6khzAjzsz24" +\
"8kHbaeAf9qfmqfCky1Jg==,MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIasAa8ogjPCKXeA" +\
"4KY3t0W3xBRmG+E4D+MNoRIAJrYuNLSYtAcOL7DCbIfgc+7c5Y4Mh/FzoEyeumKGYMoyTfg=="
user.passkey_add(passkey_str)
client.sssd.pam['pam_passkey_auth'] = 'true'
client.sssd.start()
output = client.auth.passkey.register(tc, cmd, 123456)
assert output.stdout_lines[-1] == 'user1'
"""

self.su: SUAuthenticationUtils = SUAuthenticationUtils(host)
"""
Expand Down Expand Up @@ -85,6 +110,7 @@ def test_example(client: Client, ldap: LDAP):
"""

self.ssh: SSHAuthenticationUtils = SSHAuthenticationUtils(host)

"""
Test authentication and authorization via ssh.
Expand Down Expand Up @@ -144,6 +170,108 @@ def test_example(client: Client, ldap: LDAP, kdc: KDC):
return KerberosAuthenticationUtils(self.host, ssh)


class PasskeyAuthenticationUtils(MultihostUtility[MultihostHost]):
"""
Methods for testing passkey registration and authentications
with umockdev-run command.
"""
def __init__(self, host: MultihostHost, fs: LinuxFileSystem) -> None:
"""
:param host: Multihost host.
:type host: MultihostHost
:param fs: Linux File system.
:type fs: LinuxFileSystem.
"""

super().__init__(host)
self.fs: LinuxFileSystem = fs

def register(self, tc: str, cmd: str, pin: str | int) -> SSHProcessResult:
"""
Check umockdev run, while registering the user.
:param tc: test case variable we use to save the record files.
:type tc: str
:param cmd: command we use while registering the passkey.
:type cmd: str
:param pin: pin we set while creating the umockde records.
:type pin: str | int
:return: True if command runs successful, False otherwise.
:rtype: SSHProcessResult
"""

# Command we use to run to check register key with umockdev

command = f"LD_PRELOAD=/opt/random.so umockdev-run --device /tmp/yk.umockdev " \
f"--ioctl /dev/hidraw1=/tmp/{tc}.ioctl " \
f"--script /dev/hidraw1=/tmp/{tc}.script -- {cmd}"

result = self.host.ssh.expect(rf"""
# It takes some time to get authentication failure
set timeout 15
set send_slow {{1 .1}}
spawn bash -c "{command}"
expect {{
"Enter PIN:*" {{send -- "{pin}\r"}}
}}
expect eof
""")

return result

def su(self, tc: str, username: str, pin: str | int) -> SSHProcessResult:
"""
To check authentication using umockdev command for users
:param tc: test case variable we use to save the record files
:type tc: str
:param username: name of user to authenticate
:type username: str
:param pin: pin we used while creating the record files
:type pin: str | int
:return: True if command runs successful, False otherwise.
:rtype: SSHProcessResult
"""

# umockdev command to check authentication of user with already created record files.

umock_run = f"""LD_PRELOAD=/opt/random.so umockdev-run \
--device /tmp/{tc}.device \
--script /dev/hidraw1=/tmp/{tc}.script \
--ioctl /dev/hidraw1=/tmp/{tc}.ioctl"""

preload = f"""env | grep ^UMOCKDEV_ > /etc/sysconfig/sssd; \
printf "LD_PRELOAD=$LD_PRELOAD" >> /etc/sysconfig/sssd; \
systemctl restart sssd; \
chmod -R a+rwx $UMOCKDEV_DIR"""

su = f"""su - ci -c "su - {username} -c whoami" """

command_su = f"""{umock_run} -- bash -c '{preload}; {su}'"""

self.fs.write('/tmp/runsu_latest.sh', command_su, mode="a+rwx")
result = self.host.ssh.expect(rf'''
# It takes some time to get authentication failure
set timeout 40
set send_slow {{1 .1}}
spawn bash -c "pushd /tmp; sh runsu_latest.sh"
expect {{
"Insert your passkey device, then press ENTER*" {{send -- "\r"}}
}}
expect {{
"Enter PIN:*" {{send -- "{pin}\r"}}
}}
expect eof
''')

return result


class SUAuthenticationUtils(MultihostUtility[MultihostHost]):
"""
Methods for testing authentication and authorization via su.
Expand Down
12 changes: 12 additions & 0 deletions src/tests/system/lib/sssd/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,18 @@ def tshark(self, args: list[Any] | None = None) -> SSHProcessResult:

return self.host.ssh.exec(["tshark", *args])

def copy_files(self, src: str, dest: str) -> None:
"""
Copy local file to remote hosts
:param src: source file location
:type src: str
:param dest: destination file location
:type dest: str
:return: None
"""
self.__fs.upload(src, dest)

def teardown(self):
"""
Revert all changes.
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Passkey mapping: passkey:DxUk04JimrbcKKTdjqP8vRMQLA9zCqm/uoHW3HRDIr7ztTbcXzsV2oEc4QCZIMlbEc0ZWiA4HnkEwbzAuOCMDg==,MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyrxaekpIX7AMw72mH7ZcWpwP4t0GCLccSbMse6HOYvfIatpWJC/oeWJnd4ei7XxpGu7MO2atlupS03kbKFr7VQ==
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
d 0 /dev/hidraw1

w 3 ^@�����^@^H^A^A^A^A^A^A^A^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 2 �����^@^Q^A^A^A^A^A^A^A^A�g�8^B^E^D^C^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
w 2 ^@�g�8�^@^A^D^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 3 �g�8�^@�^@�^A�fU2F_V2hFIDO_2_0lFIDO_2_1_PRE^B�kcredProtectkhmac-secr�g�8^@et^CP/�W��^SG�^V�Z�� *^D�brk�bup�dplat�iclientPin�ucredentialM�g�8^AgmtPreview�^E^Y^D�^F�^B^A^G^H^H^X�^I�cnfccusb^J��calg&dtypejpublic-key��g�8^Bcalg'dtypejpublic-key^M^D^N^Z^@^E^D^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
w 3582 ^@�g�8�^@^F^F�^A^B^B^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 2 �g�8�^@Q^@�^A�^A^B^C8^X ^A!X ��m^W�-(l�9�۝�W`�^B{e��NȈeT�@=�^\"X ���>�^R���g�8^@��^OO�P�^H��6^K�4��^Y�^JMn��^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
w 6 ^@�g�8�^@x^F�^A^B^B^E^C�^A^B^C8^X ^A!X 3�B�1�ˠ^S�^\^Ev�,�^P<Rij��,Q�\���b"X [�^M^J^@�g�8^@�G8��������5��Q\^\^U��^E�Q!^FX ^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A�^I��^K�^R�B��c^@�g�8^Ah^F"�^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 79 �g�8�^@5^@�^BX0�D��͖�J?����^O����G{l��D^O^@�^DDO�`����^[^W!�������5�^@^@^@^@
w 1 ^@�g�8�^@�^A�^AX ^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^B�bidhipa.testdnameh^@�g�8^@ipa.test^C�bidX ^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^Adnameeuser1^D^@�g�8^A��calg&dtypejpublic-key^HX ���4���As�a2.�^F؎���^\2�@�z30�̲�^I^@�g�8^B^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 199 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 287 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 289 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 290 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 288 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 287 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 289 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 289 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 288 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 289 �g�8�^@^A^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 288 �g�8�^@^A^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
r 291 �g�8�^@^A^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@�g�8�^D^H^@�^Afpacked^BXĜ^@�|���Dږ^Qx??�d^Q/N�4�/oC���}.�[E^@^@^@^B/�W��^SG�g�8^@�^V�Z�� *^@@^O^U$ӂb���(�ݎ���^S^P,^Os^J������tC"��6�_;^Uځ^\�^@� �[�g�8^A^Q�^YZ 8^^y^D������^N�^A^B^C& ^A!X ʼZzJH_�^Lý�^_�\Z�^O��^F^H�^\I�,{��b�"�g�8^BX �j�V$/�ybgw���|i^Z��;f���R�y^[(Z�U^C�calg&csigXF0D^B >�]�^K��R�g�8^C�$w����J�ˡƲ�婟C�x^RV�^B ^A�>n���nU��U�0Q�\��]���՟��^C�G�c�g�8^Dx5c�Y^B�0�^B�0�^A��^C^B^A^B^B^I^@�9*7_8��0^M^F^I*�H��^M^A^A^K^E^@0.1,0*^F^CU^D^C^S#�g�8^EYubico U2F Root CA Serial 4572006310 ^W^M140801000000Z^X^O20500�g�8^F904000000Z0n1^K0^I^F^CU^D^F^S^BSE1^R0^P^F^CU^D^J^L^IYubico AB1"0 ^F^CU^D^K^L^YAut�g�8^Ghenticator Attestation1'0%^F^CU^D^C^L^^Yubico U2F EE Serial 92551�g�8^H41600Y0^S^F^G*�H�=^B^A^F^H*�H�=^C^A^G^CB^@^D�S0��^N�ȣ��\^G�2��V^FL$]�^MSX^K�g�8^Is��G�^O�^W^U�yyhp�\^W��^C��&��o�ۆ^U�#�£��00^S^F^J+^F^A^D^A��^J^M^A^D^E^D^C�g�8^J^E^D^C0"^F^I+^F^A^D^A��^J^B^D^U1.3.6.1.4.1.41482.1.70^S^F^K+^F^A^D^A��^\^B^A^A^D^D^C^B^D�g�8^K00!^F^K+^F^A^D^A��^\^A^A^D^D^R^D^P/�W��^SG�^V�Z�� *0^L^F^CU^]^S^A^A�^D^B0^@0^M^F^I*�H���g�8^L^M^A^A^K^E^@^C�^A^A^@^Ai1d����;I^O�!/X,H��^\���_^X�"t9e�>3�J]^KbP��^N^D�<ԓ�g�8^M����pI^Hw^J^P=^VN�^Rr`C6�"̜j�^G-��x'��^_^A^^�jE�|� {V^Rg|%���5��1��g�8^NK�өuԼd~^R�,޵�/u^T^@\�b^_��*G��^Hۨ�y�%�M^V��:�E*DN^T^YvX�6^N^M^`�g�8^OE^V^N)"L�^HP�`nw��<\S�~rOoL*���2r��?Q^H�.k������[���]�Ȋ�LDN�E��g�8^P��;�3��1���V^P~#6!�^K((g�!B�^K��v�^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
Loading

0 comments on commit 9bdbcdf

Please sign in to comment.