python312Packages.pyoverkiz: 1.15.2 -> 1.15.3 (#366663)
[NixPkgs.git] / nixos / tests / password-option-override-ordering.nix
blob5b06ab0bdbff0ef83eecf93bd9e97236412e88b8
1 let
2   password1 = "foobar";
3   password2 = "helloworld";
4   hashed_bcrypt = "$2b$05$8xIEflrk2RxQtcVXbGIxs.Vl0x7dF1/JSv3cyX6JJt0npzkTCWvxK"; # fnord
5   hashed_yeshash = "$y$j9T$d8Z4EAf8P1SvM/aDFbxMS0$VnTXMp/Hnc7QdCBEaLTq5ZFOAFo2/PM0/xEAFuOE88."; # fnord
6   hashed_sha512crypt = "$6$ymzs8WINZ5wGwQcV$VC2S0cQiX8NVukOLymysTPn4v1zJoJp3NGyhnqyv/dAf4NWZsBWYveQcj6gEJr4ZUjRBRjM0Pj1L8TCQ8hUUp0"; # meow
7 in
9 import ./make-test-python.nix (
10   { pkgs, ... }:
11   {
12     name = "password-option-override-ordering";
13     meta = with pkgs.lib.maintainers; {
14       maintainers = [ fidgetingbits ];
15     };
17     nodes =
18       let
19         # The following users are expected to have the same behavior between immutable and mutable systems
20         # NOTE: Below given A -> B it implies B overrides A . Each entry below builds off the next
21         users = {
22           # mutable true/false: initialHashedPassword -> hashedPassword
23           fran = {
24             isNormalUser = true;
25             initialHashedPassword = hashed_yeshash;
26             hashedPassword = hashed_sha512crypt;
27           };
29           # mutable false: initialHashedPassword -> hashedPassword -> initialPassword
30           # mutable true: initialHashedPassword -> initialPassword -> hashedPassword
31           greg = {
32             isNormalUser = true;
33             hashedPassword = hashed_sha512crypt;
34             initialPassword = password1;
35           };
37           # mutable false: initialHashedPassword -> hashedPassword -> initialPassword -> password
38           # mutable true: initialHashedPassword -> initialPassword -> hashedPassword -> password
39           egon = {
40             isNormalUser = true;
41             initialPassword = password2;
42             password = password1;
43           };
45           # mutable true/false: hashedPassword -> password
46           # NOTE: minor duplication of test above, but to verify no initialXXX use is consistent
47           alice = {
48             isNormalUser = true;
49             hashedPassword = hashed_sha512crypt;
50             password = password1;
51           };
53           # mutable false: initialHashedPassword -> hashedPassword -> initialPassword -> password -> hashedPasswordFile
54           # mutable true: initialHashedPassword -> initialPassword -> hashedPassword -> password -> hashedPasswordFile
55           bob = {
56             isNormalUser = true;
57             hashedPassword = hashed_sha512crypt;
58             password = password1;
59             hashedPasswordFile = (pkgs.writeText "hashed_bcrypt" hashed_bcrypt).outPath; # Expect override of everything above
60           };
62           # Show hashedPassword -> password -> hashedPasswordFile -> initialPassword is false
63           # to explicitly show the following lib.trace warning in users-groups.nix (which was
64           # the wording prior to PR 310484) is in fact wrong:
65           # ```
66           # The user 'root' has multiple of the options
67           # `hashedPassword`, `password`, `hashedPasswordFile`, `initialPassword`
68           # & `initialHashedPassword` set to a non-null value.
69           # The options silently discard others by the order of precedence
70           # given above which can lead to surprising results. To resolve this warning,
71           # set at most one of the options above to a non-`null` value.
72           # ```
73           cat = {
74             isNormalUser = true;
75             hashedPassword = hashed_sha512crypt;
76             password = password1;
77             hashedPasswordFile = (pkgs.writeText "hashed_bcrypt" hashed_bcrypt).outPath;
78             initialPassword = password2; # lib.trace message implies this overrides everything above
79           };
81           # Show hashedPassword -> password -> hashedPasswordFile -> initialHashedPassword is false
82           # to also explicitly show the lib.trace explained above (see cat user) is wrong
83           dan = {
84             isNormalUser = true;
85             hashedPassword = hashed_sha512crypt;
86             initialPassword = password2;
87             password = password1;
88             hashedPasswordFile = (pkgs.writeText "hashed_bcrypt" hashed_bcrypt).outPath;
89             initialHashedPassword = hashed_yeshash; # lib.trace message implies this overrides everything above
90           };
91         };
93         mkTestMachine = mutable: {
94           environment.systemPackages = [ pkgs.shadow ];
95           users = {
96             mutableUsers = mutable;
97             inherit users;
98           };
99         };
100       in
101       {
102         immutable = mkTestMachine false;
103         mutable = mkTestMachine true;
104       };
106     testScript = ''
107       import crypt
109       def assert_password_match(machine, username, password):
110         shadow_entry = machine.succeed(f"getent shadow {username}")
111         print(shadow_entry)
112         hash = shadow_entry.split(":")[1]
113         seed = "$".join(hash.split("$")[:-1])
114         assert crypt.crypt(password, seed) == hash, f"{username} user password does not match"
116       with subtest("alice user has correct password"):
117         for machine in machines:
118           assert_password_match(machine, "alice", "${password1}")
119           assert "${hashed_sha512crypt}" not in machine.succeed("getent shadow alice"), f"{machine}: alice user password is not correct"
121       with subtest("bob user has correct password"):
122         for machine in machines:
123           print(machine.succeed("getent shadow bob"))
124           assert "${hashed_bcrypt}" in machine.succeed("getent shadow bob"), f"{machine}: bob user password is not correct"
126       with subtest("cat user has correct password"):
127         for machine in machines:
128           print(machine.succeed("getent shadow cat"))
129           assert "${hashed_bcrypt}" in machine.succeed("getent shadow cat"), f"{machine}: cat user password is not correct"
131       with subtest("dan user has correct password"):
132         for machine in machines:
133           print(machine.succeed("getent shadow dan"))
134           assert "${hashed_bcrypt}" in machine.succeed("getent shadow dan"), f"{machine}: dan user password is not correct"
136       with subtest("greg user has correct password"):
137         print(mutable.succeed("getent shadow greg"))
138         assert "${hashed_sha512crypt}" in mutable.succeed("getent shadow greg"), "greg user password is not correct"
140         assert_password_match(immutable, "greg", "${password1}")
141         assert "${hashed_sha512crypt}" not in immutable.succeed("getent shadow greg"), "greg user password is not correct"
143       for machine in machines:
144         machine.wait_for_unit("multi-user.target")
145         machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
147       def check_login(machine: Machine, tty_number: str, username: str, password: str):
148         machine.send_key(f"alt-f{tty_number}")
149         machine.wait_until_succeeds(f"[ $(fgconsole) = {tty_number} ]")
150         machine.wait_for_unit(f"getty@tty{tty_number}.service")
151         machine.wait_until_succeeds(f"pgrep -f 'agetty.*tty{tty_number}'")
152         machine.wait_until_tty_matches(tty_number, "login: ")
153         machine.send_chars(f"{username}\n")
154         machine.wait_until_tty_matches(tty_number, f"login: {username}")
155         machine.wait_until_succeeds("pgrep login")
156         machine.wait_until_tty_matches(tty_number, "Password: ")
157         machine.send_chars(f"{password}\n")
158         machine.send_chars(f"whoami > /tmp/{tty_number}\n")
159         machine.wait_for_file(f"/tmp/{tty_number}")
160         assert username in machine.succeed(f"cat /tmp/{tty_number}"), f"{machine}: {username} password is not correct"
162       with subtest("Test initialPassword override"):
163         for machine in machines:
164           check_login(machine, "2", "egon", "${password1}")
166       with subtest("Test initialHashedPassword override"):
167         for machine in machines:
168           check_login(machine, "3", "fran", "meow")
169     '';
170   }