diff --git a/src/tests/system/tests/test_netgroups.py b/src/tests/system/tests/test_netgroups.py index 87ebafd21f2..8018f1c3a99 100644 --- a/src/tests/system/tests/test_netgroups.py +++ b/src/tests/system/tests/test_netgroups.py @@ -6,10 +6,45 @@ from __future__ import annotations +import time + import pytest from sssd_test_framework.roles.client import Client from sssd_test_framework.roles.generic import GenericProvider -from sssd_test_framework.topology import KnownTopologyGroup +from sssd_test_framework.roles.ldap import LDAP +from sssd_test_framework.topology import KnownTopology, KnownTopologyGroup + + +def libc_execution(client: Client, command_list): + """ + Executes python commands in client machine. + + The function's goal is to check network group membership using the + innetgr function of libc, invoked via a Python script on the client machine. + The result is printed to the console. + """ + + command = ( + f'python -c "from ctypes import CDLL; ' + "from ctypes.util import find_library; " + "libc = CDLL(find_library('c')); " + f"x = libc.innetgr{command_list}; " + 'print(x);"' + ) + return client.host.conn.run(command).stdout + + +def create_users(ldap: LDAP): + """ + Creates users/groups needed for this test script. + """ + ou_people = ldap.ou("People").add() + ou_group = ldap.ou("groups").add() + ldap.ou("Netgroup").add() + + for id in [9000, 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9010]: + ldap.user(f"ng{id}", basedn=ou_people).add() + ldap.user(f"ng{id}", basedn=ou_group).add() @pytest.mark.importance("medium") @@ -108,3 +143,365 @@ def test_netgroups__add_remove_netgroup_member(client: Client, provider: Generic assert len(result.members) == 1 assert "(-, user-1)" not in result.members assert "(-, user-2)" in result.members + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__nisnetgrouptriple(client: Client, ldap: LDAP): + """ + :title: Netgroup with nisNetgroupTriple + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check nisNetgroupTriple contains members as added in the test. + 2. Check network group membership using the innetgr function of libc. + :expectedresults: + 1. NisNetgroupTriple should contain members as added in the test. + 2.Result is 1, indicating membership in the group. + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + client.sssd.start() + + assert "(testhost1, ng9000, ldap.test)" in client.tools.getent.netgroup("QAUsers").members + assert libc_execution(client, (b"QAUsers", None, b"ng9000", b"ldap.test")) == "1" + assert libc_execution(client, (b"QAUsers", b"testhost1", b"ng9000", b"ldap.test")) == "1" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__cache_timeout(client: Client, ldap: LDAP): + """ + :title: Decrease the cache time out and add new entry for nisNetgroupTriple + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check if the netgroup "QAUsers" contains the tuple (testhost1, ng9000, ldap.test), + verifying that the member added earlier exists. + 2. Check that (testhost1, ng9001, ldap.test) does not exist in the netgroup, + confirming that the user ng9001 has not yet been added. + 3. Add another member to the "QAUsers" netgroup. + 4. Check if ng9001 is part of the netgroup "QAUsers" using the libc_execution function. + The initial value is expected to be "0". + 5. Check if after the cache expires, the user ng9001 and host testhost2 + are now correctly considered part of the netgroup "QAUsers". + 6. Check if both tuples (testhost1, ng9000, ldap.test) and (testhost2, ng9001, ldap.test) + are present in the "QAUsers" netgroup after the changes. + :expectedresults: + 1. Netgroup "QAUsers" contains the tuple (testhost1, ng9000, ldap.test) + 2. Tuple (testhost1, ng9001, ldap.test) does not exist in the netgroup + 3. Another member should be added to the "QAUsers" netgroup. + 4. ng9001 is part of the netgroup "QAUsers" + 5. The user ng9001 and host testhost2 are now correctly considered part of the netgroup "QAUsers". + 6. Both tuples (testhost1, ng9000, ldap.test) and (testhost2, ng9001, ldap.test) + are present in the "QAUsers" netgroup after the changes. + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert "(testhost1, ng9000, ldap.test)" in client.tools.getent.netgroup("QAUsers").members + assert "(testhost1, ng9001, ldap.test)" not in client.tools.getent.netgroup("QAUsers").members + + qa_users.add_member(host="testhost2", user="ng9001", domain="ldap.test") + + assert libc_execution(client, (b"QAUsers", None, b"ng9001", b"ldap.test")) == "0" + + time.sleep(70) + + assert libc_execution(client, (b"QAUsers", None, b"ng9001", b"ldap.test")) == "1" + assert libc_execution(client, (b"QAUsers", b"testhost2", b"ng9001", b"ldap.test")) == "1" + assert libc_execution(client, (b"QAUsers", b"testhost2", None, b"ldap.test")) == "1" + + assert "(testhost1, ng9000, ldap.test)" in client.tools.getent.netgroup("QAUsers").members + assert "(testhost2, ng9001, ldap.test)" in client.tools.getent.netgroup("QAUsers").members + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__multiple_netgroups(client: Client, ldap: LDAP): + """ + :title: Create multiple netgroups + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check if the user ng9005 is part of the "DEVUsers" netgroup by calling the libc.innetgr function. + 2. Verify if the tuple (testhost5,ng9005,ldap.test) exists in the "DEVUsers" netgroup, + using the getent netgroup command. + 3. Check if the combination of host (testhost5), user (ng9005), and domain (ldap.test) + is correctly part of the "DEVUsers" netgroup using libc.innetgr. + :expectedresults: + 1. User ng9005 is part of the "DEVUsers" netgroup + 2. Tuple (testhost5,ng9005,ldap.test) exists in the "DEVUsers" netgroup + 3. Combination of host (testhost5), user (ng9005), and domain (ldap.test) + is correctly part of the "DEVUsers" netgroup + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", None, b"ng9005", b"ldap.test")) == "1" + assert "(testhost5,ng9005,ldap.test)" in client.tools.getent.netgroup("DEVUsers").members + assert libc_execution(client, (b"DEVUsers", b"testhost5", b"ng9005", b"ldap.test")) == "1" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__membernisnetgroup(client: Client, ldap: LDAP): + """ + :title: Add more complex LDAP netgroup structure by nesting one netgroup within another. + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check if the tuple (testhost5, ng9005, ldap.test) is part of the "DEVUsers" + netgroup using the libc.innetgr function, which calls the C library's innetgr function. + Since ng9005 was directly added to the "DEVUsers" group, this check should return "1" (true). + 2. Check that (testhost5, ng9005, ldap.test) is present as a direct member of "DEVUsers". + 3. Check that (testhost1, ng9000, ldap.test) is also present, + even though this tuple was added to "QAUsers", not "DEVUsers". + This confirms that the nested group membership is working correctly + (since "QAUsers" is nested within "DEVUsers"). + 4. Check if the tuple (testhost1, ng9000, ldap.test) (which belongs to "QAUsers") + is correctly recognized as part of the "DEVUsers" group, due to the nested group structure. + The expected result is "1", confirming membership. + 5. Checks if the tuple (None, unknown, None) is not part of the "DEVUsers" group. + The result should be "0" (false), meaning the unknown entity does not exist in the group. + :expectedresults: + 1. Tuple (testhost5, ng9005, ldap.test) is part of the "DEVUsers" + 2. (testhost5, ng9005, ldap.test) is present as a direct member of "DEVUsers". + 3. (testhost1, ng9000, ldap.test) is present as a direct member of "DEVUsers". + 4. Tuple (testhost1, ng9000, ldap.test) is correctly recognized as part of the "DEVUsers" group + 5. The tuple (None, unknown, None) is not part of the "DEVUsers" group. + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + ldap.ldap.modify(dev_users.dn, add={"memberNisNetgroup": "QAUsers"}) + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", b"testhost5", b"ng9005", b"ldap.test")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(testhost5, ng9005, ldap.test)" in member + assert "(testhost1, ng9000, ldap.test)" in member + + assert libc_execution(client, (b"DEVUsers", b"testhost1", b"ng9000", b"ldap.test")) == "1" + assert libc_execution(client, (b"DEVUsers", None, b"unknown", None)) == "0" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__add_dn_membernisnetgroup(client: Client, ldap: LDAP): + """ + :title: Adding dn to memberNisNetgroup + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check if the tuple (None, ng9005, ldap.test) is part of the "DEVUsers" group + using the libc.innetgr function, which calls the C library's innetgr. + Since ng9005 was directly added to "DEVUsers", this should return "1", indicating membership. + 2. Check that the tuple (testhost5, ng9005, ldap.test) is present as a direct member of "DEVUsers". + 3. Check that the tuple (testhost1, ng9000, ldap.test) is also present. + Since "QAUsers" is now referenced as part of "DEVUsers", its members + (like ng9000 on testhost1) are inherited by "DEVUsers". + 4. Checks if the tuple (testhost1, ng9000, ldap.test)—which belongs to the "QAUsers" + group—is recognized as part of "DEVUsers". + Since "QAUsers" has been nested in "DEVUsers", this check should return "1" (true). + 5. Check if a tuple (None, unknown, None) is not part of the "DEVUsers" group. + This should return "0" (false), confirming that the unknown user does not exist in the group. + :expectedresults: + 1. id look up should success. + 2. Errors should not be seen on enabling proxy_fast_alias. + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + ldap.ldap.modify(dev_users.dn, replace={"memberNisNetgroup": qa_users.dn}) + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", None, b"ng9005", b"ldap.test")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(testhost5, ng9005, ldap.test)" in member + assert "(testhost1, ng9000, ldap.test)" in member + + assert libc_execution(client, (b"DEVUsers", b"testhost1", b"ng9000", b"ldap.test")) == "1" + assert libc_execution(client, (b"DEVUsers", None, b"unknown", None)) == "0" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__different_syntax(client: Client, ldap: LDAP): + """ + :title: Using different syntax for nisNetgroupTriple + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Check if the user ng9006 is part of the "DEVUsers" group using the libc.innetgr function. + The call specifies only the user (ng9006) without a specific host or domain. + Since ng9006 was directly added to the "DEVUsers" group, + this check should return "1", indicating membership. + 2. Check that the user ng9006 appears in the group members list, represented as the tuple (-,ng9006,). + :expectedresults: + 1. The user ng9006 is part of the "DEVUsers" group + 2. The user ng9006 appears in the group members list + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + dev_users.add_member(user="ng9006") + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", None, b"ng9006", b"ldap.test")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(-,ng9006,)" in member + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__host_and_domain(client: Client, ldap: LDAP): + """ + :title: A scenario where an LDAP netgroup contains a member that + only has a host and domain specified, but no associated user. + :setup: + 1. Check if the tuple (samplehost, None, samplehost.domain.com)—representing a + host samplehost with the domain samplehost.domain.com and no user—is part of the + "DEVUsers" group using the libc.innetgr function. + Since this host and domain combination was directly added to + "DEVUsers", the function should return "1", indicating membership. + 2. Check that the tuple (samplehost, -, samplehost.domain.com) is part of the group + :expectedresults: + 1. The tuple (samplehost, None, samplehost.domain.com) is part of the "DEVUsers" + 2. The tuple (samplehost, -, samplehost.domain.com) is part of the group + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + dev_users.add_member(host="samplehost", domain="samplehost.domain.com") + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", b"samplehost", None, b"samplehost.domain.com")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(samplehost,-,samplehost.domain.com)" in member + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_netgroup__with_nested_loop(client: Client, ldap: LDAP): + """ + :title: Create and manages nested LDAP netgroups and tests their behavior + through several scenarios involving caching, membership queries, and restarts of the SSSD service. + :setup: + 1. Create users, groups and start sssd. + :steps: + 1. Checks if the tuple (testhost5, ng9005, ldap.test) is part of the "DEVUsers" group. + Since ng9005 was directly added, this should return "1" (membership confirmed). + 2. Retrieves all members of the "DEVUsers" group using the getent netgroup tool. + 3. Check for ng9000: Verifies that ng9000 (from QAUsers) is also part of "DEVUsers". + 4. Checks if a user random (who is not in any netgroup) is part of "DEVUsers". + 5. After the restart, the script checks if ng9005 is a member of "QAUsers", + which should return "1" because of the circular nesting between "DEVUsers" and "QAUsers". + 6. After the SSSD restart, it retrieves the members of "DEVUsers" again to ensure they are still intact. + 7. Membership check for ng9000: Verifies that ng9000 (from QAUsers) is part of the "QAUsers" group. + 8. Confirm that an unknown user is not part of "QAUsers". + :expectedresults: + 1. The tuple (testhost5, ng9005, ldap.test) is part of the "DEVUsers" + 2. All members of the "DEVUsers" group be there + 3. ng9000 (from QAUsers) is also part of "DEVUsers" + 4. random (who is not in any netgroup) is not part of "DEVUsers". + 5. ng9005 is a member of "QAUsers" + 6. All members of the "DEVUsers" group be there + 7. ng9000 (from QAUsers) is part of the "QAUsers" group + 8. unknown user is not part of "QAUsers" + :customerscenario: False + """ + ou = ldap.ou("Netgroup") + create_users(ldap) + + qa_users = ldap.netgroup("QAUsers", basedn=ou).add() + qa_users.add_member(host="testhost1", user="ng9000", domain="ldap.test") + + dev_users = ldap.netgroup("DEVUsers", basedn=ou).add() + ldap.ldap.modify(dev_users.dn, add={"memberNisNetgroup": qa_users.dn}) + dev_users.add_member(host="testhost5", user="ng9005", domain="ldap.test") + dev_users.add_member(user="ng9006") + + ldap.ldap.modify(qa_users.dn, add={"memberNisNetgroup": dev_users.dn}) + + client.sssd.dom("test")["entry_cache_timeout"] = "60" + client.sssd.start() + + assert libc_execution(client, (b"DEVUsers", b"testhost5", b"ng9005", b"ldap.test")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(testhost1,ng9000,ldap.test)" in member + assert "(-,ng9006,)" in member + assert "(testhost5,ng9005,ldap.test)" in member + + assert libc_execution(client, (b"DEVUsers", None, b"ng9000", b"ldap.test")) == "1" + assert libc_execution(client, (b"DEVUsers", None, b"random", None)) == "0" + + client.sssd.restart() + + assert libc_execution(client, (b"QAUsers", None, b"ng9005", b"ldap.test")) == "1" + + member = client.tools.getent.netgroup("DEVUsers").members + assert "(testhost1,ng9000,ldap.test)" in member + assert "(-,ng9006,)" in member + assert "(testhost5,ng9005,ldap.test)" in member + + assert libc_execution(client, (b"QAUsers", None, b"ng9000", b"ldap.test")) == "1" + assert libc_execution(client, (b"QAUsers", None, b"unknown", None)) == "0"