1import ./make-test-python.nix ({ pkgs, lib, ... }:
2
3let
4 dbUser = "nixos_auth";
5 dbPassword = "topsecret123";
6 dbName = "auth";
7
8 mysqlUsername = "mysqltest";
9 mysqlPassword = "topsecretmysqluserpassword123";
10 mysqlGroup = "mysqlusers";
11
12 localUsername = "localtest";
13 localPassword = "topsecretlocaluserpassword123";
14
15 mysqlInit = pkgs.writeText "mysqlInit" ''
16 CREATE USER '${dbUser}'@'localhost' IDENTIFIED BY '${dbPassword}';
17 CREATE DATABASE ${dbName};
18 GRANT ALL PRIVILEGES ON ${dbName}.* TO '${dbUser}'@'localhost';
19 FLUSH PRIVILEGES;
20
21 USE ${dbName};
22 CREATE TABLE `groups` (
23 rowid int(11) NOT NULL auto_increment,
24 gid int(11) NOT NULL,
25 name char(255) NOT NULL,
26 PRIMARY KEY (rowid)
27 );
28
29 CREATE TABLE `users` (
30 name varchar(255) NOT NULL,
31 uid int(11) NOT NULL auto_increment,
32 gid int(11) NOT NULL,
33 password varchar(255) NOT NULL,
34 PRIMARY KEY (uid),
35 UNIQUE (name)
36 ) AUTO_INCREMENT=5000;
37
38 INSERT INTO `users` (name, uid, gid, password) VALUES
39 ('${mysqlUsername}', 5000, 5000, SHA2('${mysqlPassword}', 256));
40 INSERT INTO `groups` (name, gid) VALUES ('${mysqlGroup}', 5000);
41 '';
42in
43{
44 name = "auth-mysql";
45 meta.maintainers = with lib.maintainers; [ netali ];
46
47 nodes.machine =
48 { ... }:
49 {
50 services.mysql = {
51 enable = true;
52 package = pkgs.mariadb;
53 settings.mysqld.bind-address = "127.0.0.1";
54 initialScript = mysqlInit;
55 };
56
57 users.users.${localUsername} = {
58 isNormalUser = true;
59 password = localPassword;
60 };
61
62 security.pam.services.login.makeHomeDir = true;
63
64 users.mysql = {
65 enable = true;
66 host = "127.0.0.1";
67 user = dbUser;
68 database = dbName;
69 passwordFile = "${builtins.toFile "dbPassword" dbPassword}";
70 pam = {
71 table = "users";
72 userColumn = "name";
73 passwordColumn = "password";
74 passwordCrypt = "sha256";
75 disconnectEveryOperation = true;
76 };
77 nss = {
78 getpwnam = ''
79 SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
80 FROM users \
81 WHERE name='%1$s' \
82 LIMIT 1
83 '';
84 getpwuid = ''
85 SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
86 FROM users \
87 WHERE id=%1$u \
88 LIMIT 1
89 '';
90 getspnam = ''
91 SELECT name, password, 1, 0, 99999, 7, 0, -1, 0 \
92 FROM users \
93 WHERE name='%1$s' \
94 LIMIT 1
95 '';
96 getpwent = ''
97 SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
98 FROM users
99 '';
100 getspent = ''
101 SELECT name, password, 1, 0, 99999, 7, 0, -1, 0 \
102 FROM users
103 '';
104 getgrnam = ''
105 SELECT name, 'x', gid FROM groups WHERE name='%1$s' LIMIT 1
106 '';
107 getgrgid = ''
108 SELECT name, 'x', gid FROM groups WHERE gid='%1$u' LIMIT 1
109 '';
110 getgrent = ''
111 SELECT name, 'x', gid FROM groups
112 '';
113 memsbygid = ''
114 SELECT name FROM users WHERE gid=%1$u
115 '';
116 gidsbymem = ''
117 SELECT gid FROM users WHERE name='%1$s'
118 '';
119 };
120 };
121 };
122
123 testScript = ''
124 def switch_to_tty(tty_number):
125 machine.fail(f"pgrep -f 'agetty.*tty{tty_number}'")
126 machine.send_key(f"alt-f{tty_number}")
127 machine.wait_until_succeeds(f"[ $(fgconsole) = {tty_number} ]")
128 machine.wait_for_unit(f"getty@tty{tty_number}.service")
129 machine.wait_until_succeeds(f"pgrep -f 'agetty.*tty{tty_number}'")
130
131
132 def try_login(tty_number, username, password):
133 machine.wait_until_tty_matches(tty_number, "login: ")
134 machine.send_chars(f"{username}\n")
135 machine.wait_until_tty_matches(tty_number, f"login: {username}")
136 machine.wait_until_succeeds("pgrep login")
137 machine.wait_until_tty_matches(tty_number, "Password: ")
138 machine.send_chars(f"{password}\n")
139
140
141 machine.wait_for_unit("multi-user.target")
142 machine.wait_for_unit("mysql.service")
143 machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
144
145 with subtest("Local login"):
146 switch_to_tty("2")
147 try_login("2", "${localUsername}", "${localPassword}")
148
149 machine.wait_until_succeeds("pgrep -u ${localUsername} bash")
150 machine.send_chars("id > local_id.txt\n")
151 machine.wait_for_file("/home/${localUsername}/local_id.txt")
152 machine.succeed("cat /home/${localUsername}/local_id.txt | grep 'uid=1000(${localUsername}) gid=100(users) groups=100(users)'")
153
154 with subtest("Local incorrect login"):
155 switch_to_tty("3")
156 try_login("3", "${localUsername}", "wrongpassword")
157
158 machine.wait_until_tty_matches("3", "Login incorrect")
159 machine.wait_until_tty_matches("3", "login:")
160
161 with subtest("MySQL login"):
162 switch_to_tty("4")
163 try_login("4", "${mysqlUsername}", "${mysqlPassword}")
164
165 machine.wait_until_succeeds("pgrep -u ${mysqlUsername} bash")
166 machine.send_chars("id > mysql_id.txt\n")
167 machine.wait_for_file("/home/${mysqlUsername}/mysql_id.txt")
168 machine.succeed("cat /home/${mysqlUsername}/mysql_id.txt | grep 'uid=5000(${mysqlUsername}) gid=5000(${mysqlGroup}) groups=5000(${mysqlGroup})'")
169
170 with subtest("MySQL incorrect login"):
171 switch_to_tty("5")
172 try_login("5", "${mysqlUsername}", "wrongpassword")
173
174 machine.wait_until_tty_matches("5", "Login incorrect")
175 machine.wait_until_tty_matches("5", "login:")
176 '';
177})