at 25.11-pre 7.8 kB view raw
1let 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 7in 8 9import ./make-test-python.nix ( 10 { pkgs, ... }: 11 { 12 name = "password-option-override-ordering"; 13 meta = with pkgs.lib.maintainers; { 14 maintainers = [ fidgetingbits ]; 15 }; 16 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 }; 28 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 }; 36 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 }; 44 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 }; 52 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 }; 61 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 }; 80 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 }; 92 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 }; 105 106 testScript = '' 107 import crypt 108 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" 115 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" 120 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" 125 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" 130 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" 135 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" 139 140 assert_password_match(immutable, "greg", "${password1}") 141 assert "${hashed_sha512crypt}" not in immutable.succeed("getent shadow greg"), "greg user password is not correct" 142 143 for machine in machines: 144 machine.wait_for_unit("multi-user.target") 145 machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'") 146 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" 161 162 with subtest("Test initialPassword override"): 163 for machine in machines: 164 check_login(machine, "2", "egon", "${password1}") 165 166 with subtest("Test initialHashedPassword override"): 167 for machine in machines: 168 check_login(machine, "3", "fran", "meow") 169 ''; 170 } 171)