1"""
2Integration tests for modules/useradd.py and modules/win_useradd.py
3"""
4import pytest
5from tests.support.helpers import random_string, requires_system_grains
6
7pytestmark = [
8    pytest.mark.windows_whitelisted,
9    pytest.mark.skip_unless_on_windows,
10]
11
12
13@pytest.fixture(scope="function")
14def setup_teardown_vars(salt_call_cli):
15    user_name = random_string("RS-", lowercase=False)
16    group_name = random_string("RS-", lowercase=False)
17    try:
18        yield user_name, group_name
19    finally:
20        salt_call_cli.run("user.delete", user_name, True, True)
21        salt_call_cli.run("group.delete", group_name)
22        salt_call_cli.run("lgpo.set", "computer_policy={'Minimum Password Length': 0}")
23
24
25@pytest.mark.skip_on_windows(reason="Windows does not do user checks")
26@pytest.mark.destructive_test
27@pytest.mark.skip_if_not_root
28@requires_system_grains
29def test_groups_includes_primary(setup_teardown_vars, grains, salt_call_cli):
30    # Let's create a user, which usually creates the group matching the
31    # name
32    uname = random_string("RS-", lowercase=False)
33    ret = salt_call_cli.run("user.add", uname)
34    if ret.json is False:
35        # Skip because creating is not what we're testing here
36        salt_call_cli.run("user.delete", [uname, True, True])
37        pytest.skip("Failed to create user")
38
39    try:
40        uinfo = salt_call_cli.run("user.info", uname)
41        if grains["os_family"] in ("Suse",):
42            assert "users" in uinfo.json["groups"]
43        else:
44            assert uname in uinfo.json["groups"]
45
46        # This uid is available, store it
47        uid = uinfo.json["uid"]
48
49        salt_call_cli.run("user.delete", uname, True, True)
50
51        # Now, a weird group id
52        gname = random_string("RS-", lowercase=False)
53        ret = salt_call_cli.run("group.add", gname)
54        if ret.json is False:
55            salt_call_cli.run("group.delete", gname, True, True)
56            pytest.skip("Failed to create group")
57
58        ginfo = salt_call_cli.run("group.info", gname)
59        ginfo = ginfo.json
60
61        # And create the user with that gid
62        ret = salt_call_cli.run("user.add", uname, uid, ginfo["gid"])
63        if ret.json is False:
64            # Skip because creating is not what we're testing here
65            salt_call_cli.run("user.delete", [uname, True, True])
66            pytest.skip("Failed to create user")
67
68        uinfo = salt_call_cli.run("user.info", uname)
69        assert gname in uinfo.json["groups"]
70
71    except AssertionError:
72        pytest.raises(salt_call_cli.run("user.delete", [uname, True, True]))
73
74
75@pytest.mark.skip_on_windows(reason="Windows does not do user checks")
76@pytest.mark.destructive_test
77@pytest.mark.skip_if_not_root
78def test_user_primary_group(setup_teardown_vars, salt_call_cli):
79    """
80    Tests the primary_group function
81    """
82    name = "saltyuser"
83
84    # Create a user to test primary group function
85    ret = salt_call_cli.run("user.add", name)
86    if ret.json is False:
87        salt_call_cli.run("user.delete", name)
88        pytest.skip("Failed to create a user")
89
90    # Test useradd.primary_group
91    primary_group = salt_call_cli.run("user.primary_group", name)
92    uid_info = salt_call_cli.run("user.info", name)
93    assert primary_group.json in uid_info.json["groups"]
94
95
96@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
97@pytest.mark.destructive_test
98def test_add_user(setup_teardown_vars, salt_call_cli):
99    """
100    Test adding a user.
101    """
102    user_name = setup_teardown_vars[0]
103    salt_call_cli.run("user.add", user_name)
104    user_add = salt_call_cli.run("user.list_users")
105    assert user_name in user_add.json
106
107
108@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
109@pytest.mark.destructive_test
110def test_add_group(setup_teardown_vars, salt_call_cli):
111    """
112    Test adding a user and check its apart of a group.
113    """
114    group_name = setup_teardown_vars[1]
115    salt_call_cli.run("group.add", group_name)
116    group_list = salt_call_cli.run("group.list_groups")
117    assert group_name in group_list.json
118
119
120@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
121@pytest.mark.destructive_test
122def test_add_user_to_group(setup_teardown_vars, salt_call_cli):
123    """
124    Test adding a user to a group.
125    """
126    user_name = setup_teardown_vars[0]
127    group_name = setup_teardown_vars[1]
128
129    salt_call_cli.run("group.add", group_name)
130    # And create the user as a member of that group
131    salt_call_cli.run("user.add", user_name, groups=group_name)
132
133    user_info = salt_call_cli.run("user.info", user_name)
134    assert group_name in user_info.json["groups"]
135
136
137@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
138@pytest.mark.destructive_test
139def test_add_user_addgroup(setup_teardown_vars, salt_call_cli):
140    """
141    Test adding a user to a group with groupadd.
142    """
143    user_name = setup_teardown_vars[0]
144    group_name = setup_teardown_vars[1]
145
146    salt_call_cli.run("group.add", group_name)
147    salt_call_cli.run("user.add", user_name)
148
149    salt_call_cli.run("user.addgroup", user_name, group_name)
150    info = salt_call_cli.run("user.info", user_name)
151    assert [group_name] == info.json["groups"]
152
153
154@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
155@pytest.mark.destructive_test
156def test_user_chhome(setup_teardown_vars, salt_call_cli):
157    """
158    Test changing a users home dir.
159    """
160    user_dir = r"c:\salt"
161    user_name = setup_teardown_vars[0]
162    salt_call_cli.run("user.add", user_name)
163    salt_call_cli.run("user.chhome", user_name, user_dir)
164
165    info = salt_call_cli.run("user.info", user_name)
166    assert user_dir == info.json["home"]
167
168
169@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
170@pytest.mark.destructive_test
171def test_user_chprofile(setup_teardown_vars, salt_call_cli):
172    """
173    Test changing a users profile.
174    """
175    config = r"c:\salt\config"
176    user_name = setup_teardown_vars[0]
177    salt_call_cli.run("user.add", user_name)
178
179    salt_call_cli.run("user.chprofile", user_name, config)
180    info = salt_call_cli.run("user.info", user_name)
181    assert config == info.json["profile"]
182
183
184@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
185@pytest.mark.destructive_test
186def test_user_chfullname(setup_teardown_vars, salt_call_cli):
187    """
188    Test changing a users fullname.
189    """
190    name = "Salt Test"
191    user_name = setup_teardown_vars[0]
192    salt_call_cli.run("user.add", user_name)
193
194    salt_call_cli.run("user.chfullname", user_name, name)
195    info = salt_call_cli.run("user.info", user_name)
196    assert name == info.json["fullname"]
197
198
199@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
200@pytest.mark.destructive_test
201def test_user_delete(setup_teardown_vars, salt_call_cli):
202    """
203    Test deleting a user.
204    """
205    user_name = setup_teardown_vars[0]
206    salt_call_cli.run("user.add", user_name)
207    salt_call_cli.run("user.delete", user_name)
208    ret = salt_call_cli.run("user.info", user_name)
209    assert {} == ret.json
210
211
212@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
213@pytest.mark.destructive_test
214def test_user_removegroup(setup_teardown_vars, salt_call_cli):
215    """
216    Test removing a group.
217    """
218    user_name = setup_teardown_vars[0]
219    group_name = setup_teardown_vars[1]
220
221    salt_call_cli.run("user.add", user_name)
222    salt_call_cli.run("group.add", group_name)
223
224    salt_call_cli.run("user.addgroup", user_name, group_name)
225    ret = salt_call_cli.run("user.list_groups", user_name)
226    assert [group_name] == ret.json
227
228    salt_call_cli.run("user.removegroup", user_name, group_name)
229    ret = salt_call_cli.run("user.list_groups", user_name)
230    assert [group_name] not in ret.json
231
232
233@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
234@pytest.mark.destructive_test
235def test_user_rename(setup_teardown_vars, salt_call_cli):
236    """
237    Test changing a users name.
238    """
239    name = "newuser"
240    user_name = setup_teardown_vars[0]
241    salt_call_cli.run("user.add", user_name)
242
243    salt_call_cli.run("user.rename", user_name, name)
244    info = salt_call_cli.run("user.info", name)
245
246    assert info.json["active"] is True
247
248
249@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
250@pytest.mark.destructive_test
251def test_user_setpassword(setup_teardown_vars, salt_call_cli):
252    """
253    Test setting a password.
254    """
255    passwd = "sup3rs3cr3T!"
256    user_name = setup_teardown_vars[0]
257
258    salt_call_cli.run("user.add", user_name)
259    ret = salt_call_cli.run("user.setpassword", user_name, passwd)
260    assert ret.json is True
261
262
263@pytest.mark.skip_unless_on_windows(reason="Test is only applicable to Windows.")
264@pytest.mark.destructive_test
265def test_user_setpassword_policy(setup_teardown_vars, salt_call_cli):
266    """
267    Test setting a password with a password policy.
268    """
269    passwd = "test"
270    user_name = setup_teardown_vars[0]
271
272    # attempt to set a password policy that will cause a failure when creating a user
273    salt_call_cli.run("lgpo.set", "computer_policy={'Minimum Password Length': 8}")
274    ret = salt_call_cli.run("user.add", user_name, password=passwd)
275
276    # fix the policy and store the previous strerror in ret to cleanup
277    salt_call_cli.run("lgpo.set", "computer_policy={'Minimum Password Length': 0}")
278    assert (
279        ret.json == "The password does not meet the password policy requirements."
280        " Check the minimum password length, password complexity and"
281        " password history requirements."
282    )
283