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 Mar 22, 2023
1 parent cc0545b commit 97e6184
Show file tree
Hide file tree
Showing 31 changed files with 2,679 additions and 4 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 @@ -390,6 +390,30 @@ def modify(
self._modify(attrs, input=password)
return self

def passkey_add(self, passkey_mapping: str | None = None ) -> 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 | None = None) -> 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
11 changes: 11 additions & 0 deletions src/tests/system/lib/sssd/roles/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ def add(
shadowMax: int | None = None,
shadowWarning: int | None = None,
shadowLastChange: int | None = None,
passkey: str | None = None,
) -> LDAPUser:
"""
Create new LDAP user.
Expand Down Expand Up @@ -617,6 +618,8 @@ def add(
:type shadowWarning: int | None, optional
:param shadowLastChange: shadowlastchage LDAP attribute, defaults to None
:type shadowLastChange: int | None, optional
:param passkey: passkey mapping string LDAP attributes, defaults to None
:type passkey: str | None, optional
:return: Self.
:rtype: LDAPUser
"""
Expand All @@ -642,11 +645,15 @@ def add(
"shadowMax": shadowMax,
"shadowWarning": shadowWarning,
"shadowLastChange": shadowLastChange,
"passkey": passkey,
}

if to_list_without_none([shadowMin, shadowMax, shadowWarning, shadowLastChange]):
attrs["objectClass"].append("shadowAccount")

if to_list_without_none([passkey]):
attrs["objectClass"].append("passkeyUser")

self._add(attrs)
return self

Expand All @@ -663,6 +670,7 @@ def modify(
shadowMax: int | DeleteAttribute | None = None,
shadowWarning: int | DeleteAttribute | None = None,
shadowLastChange: int | DeleteAttribute | None = None,
passkey: str | DeleteAttribute | None = None,
) -> LDAPUser:
"""
Modify existing LDAP user.
Expand All @@ -688,6 +696,8 @@ def modify(
:type shadowWarning: int | DeleteAttribute | None, optional
:param shadowLastChange: shadowlastchage LDAP attribute, defaults to None
:type shadowLastChange: int | DeleteAttribute | None, optional
:param passkey: passkey LDAP attribute, defaults to None
:type passkey: str | DeleteAttribute | None, optional
:return: Self.
:rtype: LDAPUser
"""
Expand All @@ -702,6 +712,7 @@ def modify(
"shadowMax": shadowMax,
"shadowWarning": shadowWarning,
"shadowLastChange": shadowLastChange,
"passkey": passkey,
}

self._set(attrs)
Expand Down
128 changes: 125 additions & 3 deletions src/tests/system/lib/sssd/utils/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
from __future__ import annotations

from datetime import datetime
from typing import Any
from typing import TYPE_CHECKING

from pytest_mh import MultihostHost, MultihostUtility
from pytest_mh.ssh import SSHClient, SSHProcessResult

if TYPE_CHECKING:
from pytest_mh.utils.fs import LinuxFileSystem

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


Expand Down Expand Up @@ -43,12 +47,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, ldap: IPA):
user_add = ipa.user('user1').add()
passkey_str = "passkey:NUZMRUXIb/W8Ij1GqwCDHSCWxt/SxWxckwtQjLYi/X6Y1qZFB+HI8WO6khzAjzsz24" +\
"8kHbaeAf9qfmqfCky1Jg==,MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIasAa8ogjPCKXeA" +\
"4KY3t0W3xBRmG+E4D+MNoRIAJrYuNLSYtAcOL7DCbIfgc+7c5Y4Mh/FzoEyeumKGYMoyTfg=="
user_add.passkey_add(passkey_str)
client.sssd.pam['pam_passkey_auth'] = 'true'
client.sssd.start()
output = client.auth.passkey.register(tc, 'user1', 123456)
assert output.stdout_lines[-1] == 'user1'
"""

self.su: SUAuthenticationUtils = SUAuthenticationUtils(host)
"""
Expand Down Expand Up @@ -85,6 +111,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 +171,101 @@ 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 10
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.

command_su = f"""LD_PRELOAD=/opt/random.so umockdev-run --device /tmp/{tc}.device """ + \
f"""--script /dev/hidraw1=/tmp/{tc}.script --ioctl /dev/hidraw1=/tmp/{tc}.ioctl -- """ + \
f"""bash -c 'env | grep ^UMOCKDEV_ > /etc/sysconfig/sssd; printf "LD_PRELOAD=""" + \
f"""$LD_PRELOAD" >> /etc/sysconfig/sssd; systemctl restart sssd; chmod -R a+rwx """ + \
f"""$UMOCKDEV_DIR; su - ci -c "su - {username} -c whoami"'"""

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 Expand Up @@ -673,7 +795,7 @@ def cache_count(self) -> int:

return len(result.stdout_lines) - 2

def list_principals(self, env: dict[str, Any] = dict()) -> dict[str, list[str]]:
def list_principals(self, env: dict[str, TYPE_CHECKING] = dict()) -> dict[str, list[str]]:
"""
List all principals that have existing credential cache.
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 97e6184

Please sign in to comment.