143 lines
4.2 KiB
Python
143 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
def test_parse_login_defs_parses_known_keys(tmp_path: Path):
|
|
from enroll.accounts import parse_login_defs
|
|
|
|
p = tmp_path / "login.defs"
|
|
p.write_text(
|
|
"""
|
|
# comment
|
|
UID_MIN 1000
|
|
UID_MAX 60000
|
|
SYS_UID_MIN 100
|
|
SYS_UID_MAX 999
|
|
UID_MIN not_an_int
|
|
OTHER 123
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
vals = parse_login_defs(str(p))
|
|
assert vals["UID_MIN"] == 1000
|
|
assert vals["UID_MAX"] == 60000
|
|
assert vals["SYS_UID_MIN"] == 100
|
|
assert vals["SYS_UID_MAX"] == 999
|
|
assert "OTHER" not in vals
|
|
|
|
|
|
def test_parse_passwd_and_group_and_ssh_files(tmp_path: Path):
|
|
from enroll.accounts import find_user_ssh_files, parse_group, parse_passwd
|
|
|
|
passwd = tmp_path / "passwd"
|
|
passwd.write_text(
|
|
"\n".join(
|
|
[
|
|
"root:x:0:0:root:/root:/bin/bash",
|
|
"# comment",
|
|
"alice:x:1000:1000:Alice:/home/alice:/bin/bash",
|
|
"bob:x:1001:1000:Bob:/home/bob:/usr/sbin/nologin",
|
|
"badline",
|
|
"cathy:x:notint:1000:Cathy:/home/cathy:/bin/bash",
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
group = tmp_path / "group"
|
|
group.write_text(
|
|
"\n".join(
|
|
[
|
|
"root:x:0:",
|
|
"users:x:1000:alice,bob",
|
|
"admins:x:1002:alice",
|
|
"badgroup:x:notint:alice",
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
rows = parse_passwd(str(passwd))
|
|
assert ("alice", 1000, 1000, "Alice", "/home/alice", "/bin/bash") in rows
|
|
assert all(r[0] != "cathy" for r in rows) # skipped invalid UID
|
|
|
|
gid_to_name, name_to_gid, members = parse_group(str(group))
|
|
assert gid_to_name[1000] == "users"
|
|
assert name_to_gid["admins"] == 1002
|
|
assert "alice" in members["admins"]
|
|
|
|
# ssh discovery: only authorized_keys, no symlinks
|
|
home = tmp_path / "home" / "alice"
|
|
sshdir = home / ".ssh"
|
|
sshdir.mkdir(parents=True)
|
|
ak = sshdir / "authorized_keys"
|
|
ak.write_text("ssh-ed25519 AAA...", encoding="utf-8")
|
|
# a symlink should be ignored
|
|
(sshdir / "authorized_keys2").write_text("x", encoding="utf-8")
|
|
os.symlink(str(sshdir / "authorized_keys2"), str(sshdir / "authorized_keys_link"))
|
|
assert find_user_ssh_files(str(home)) == [str(ak)]
|
|
|
|
|
|
def test_collect_non_system_users(monkeypatch, tmp_path: Path):
|
|
import enroll.accounts as a
|
|
|
|
orig_parse_login_defs = a.parse_login_defs
|
|
orig_parse_passwd = a.parse_passwd
|
|
orig_parse_group = a.parse_group
|
|
|
|
# Provide controlled passwd/group/login.defs inputs via monkeypatch.
|
|
passwd = tmp_path / "passwd"
|
|
passwd.write_text(
|
|
"\n".join(
|
|
[
|
|
"root:x:0:0:root:/root:/bin/bash",
|
|
"nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin",
|
|
"alice:x:1000:1000:Alice:/home/alice:/bin/bash",
|
|
"sysuser:x:200:200:Sys:/home/sys:/bin/bash",
|
|
"bob:x:1001:1000:Bob:/home/bob:/bin/false",
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
group = tmp_path / "group"
|
|
group.write_text(
|
|
"\n".join(
|
|
[
|
|
"users:x:1000:alice,bob",
|
|
"admins:x:1002:alice",
|
|
"",
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
defs = tmp_path / "login.defs"
|
|
defs.write_text("UID_MIN 1000\n", encoding="utf-8")
|
|
|
|
monkeypatch.setattr(
|
|
a, "parse_login_defs", lambda path=str(defs): orig_parse_login_defs(path)
|
|
)
|
|
monkeypatch.setattr(
|
|
a, "parse_passwd", lambda path=str(passwd): orig_parse_passwd(path)
|
|
)
|
|
monkeypatch.setattr(
|
|
a, "parse_group", lambda path=str(group): orig_parse_group(path)
|
|
)
|
|
|
|
# Use a stable fake ssh discovery.
|
|
monkeypatch.setattr(
|
|
a, "find_user_ssh_files", lambda home: [f"{home}/.ssh/authorized_keys"]
|
|
)
|
|
|
|
users = a.collect_non_system_users()
|
|
assert [u.name for u in users] == ["alice"]
|
|
u = users[0]
|
|
assert u.primary_group == "users"
|
|
assert u.supplementary_groups == ["admins"]
|
|
assert u.ssh_files == ["/home/alice/.ssh/authorized_keys"]
|