mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
testing htpasswd
This commit is contained in:
parent
b8e3ceef6d
commit
008554ce4b
@ -27,7 +27,9 @@ import tempfile
|
||||
import contextlib
|
||||
import argparse
|
||||
|
||||
from typing import List
|
||||
from typing import Generator
|
||||
from typing import Optional
|
||||
|
||||
import passlib.apache
|
||||
|
||||
@ -74,7 +76,7 @@ def _get_htpasswd_for_write(config: Section) -> Generator[passlib.apache.Htpassw
|
||||
|
||||
# ====
|
||||
def _cmd_list(config: Section, _: argparse.Namespace) -> None:
|
||||
for user in passlib.apache.HtpasswdFile(_get_htpasswd_path(config)).users():
|
||||
for user in sorted(passlib.apache.HtpasswdFile(_get_htpasswd_path(config)).users()):
|
||||
print(user)
|
||||
|
||||
|
||||
@ -95,8 +97,8 @@ def _cmd_delete(config: Section, options: argparse.Namespace) -> None:
|
||||
|
||||
|
||||
# =====
|
||||
def main() -> None:
|
||||
(parent_parser, argv, config) = init(add_help=False)
|
||||
def main(argv: Optional[List[str]]=None) -> None:
|
||||
(parent_parser, argv, config) = init(add_help=False, argv=argv)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="kvmd-htpasswd",
|
||||
description="Manage KVMD users (basic auth only)",
|
||||
|
||||
@ -39,6 +39,7 @@ deps =
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-asyncio
|
||||
pytest-mock
|
||||
-rrequirements.txt
|
||||
|
||||
[testenv:eslint]
|
||||
|
||||
152
tests/test_app_htpasswd.py
Normal file
152
tests/test_app_htpasswd.py
Normal file
@ -0,0 +1,152 @@
|
||||
# ========================================================================== #
|
||||
# #
|
||||
# KVMD - The main Pi-KVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# ========================================================================== #
|
||||
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import tempfile
|
||||
import builtins
|
||||
import getpass
|
||||
|
||||
from typing import List
|
||||
from typing import Generator
|
||||
from typing import Any
|
||||
|
||||
import passlib.apache
|
||||
|
||||
import pytest
|
||||
|
||||
from kvmd.apps.htpasswd import main
|
||||
|
||||
|
||||
# =====
|
||||
def _make_passwd(user: str) -> str:
|
||||
return hashlib.md5(user.encode()).hexdigest()
|
||||
|
||||
|
||||
@pytest.fixture(name="htpasswd", params=[[], ["admin"], ["admin", "user"]])
|
||||
def _htpasswd_fixture(request) -> Generator[passlib.apache.HtpasswdFile, None, None]: # type: ignore
|
||||
(fd, path) = tempfile.mkstemp()
|
||||
os.close(fd)
|
||||
htpasswd = passlib.apache.HtpasswdFile(path)
|
||||
for user in request.param:
|
||||
htpasswd.set_password(user, _make_passwd(user))
|
||||
htpasswd.save()
|
||||
yield htpasswd
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def _run_main(htpasswd: passlib.apache.HtpasswdFile, cmd: List[str]) -> None:
|
||||
main([
|
||||
"kvmd-htpasswd",
|
||||
*cmd,
|
||||
"--set-options",
|
||||
"kvmd/auth/basic/htpasswd=" + htpasswd.path,
|
||||
"kvmd/hid/device=/dev/null",
|
||||
])
|
||||
|
||||
|
||||
# =====
|
||||
def test_main__list(htpasswd: passlib.apache.HtpasswdFile, capsys) -> None: # type: ignore
|
||||
_run_main(htpasswd, ["list"])
|
||||
(out, err) = capsys.readouterr()
|
||||
assert len(err) == 0
|
||||
assert sorted(filter(None, out.split("\n"))) == sorted(htpasswd.users()) == sorted(set(htpasswd.users()))
|
||||
|
||||
|
||||
# =====
|
||||
def test_main__set__change_stdin(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore
|
||||
old_users = set(htpasswd.users())
|
||||
if old_users:
|
||||
assert htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
|
||||
mocker.patch.object(builtins, "input", (lambda: " test "))
|
||||
_run_main(htpasswd, ["set", "admin", "--read-stdin"])
|
||||
|
||||
htpasswd.load(force=True)
|
||||
assert htpasswd.check_password("admin", " test ")
|
||||
assert old_users == set(htpasswd.users())
|
||||
|
||||
|
||||
def test_main__set__add_stdin(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore
|
||||
old_users = set(htpasswd.users())
|
||||
if old_users:
|
||||
mocker.patch.object(builtins, "input", (lambda: " test "))
|
||||
_run_main(htpasswd, ["set", "new", "--read-stdin"])
|
||||
|
||||
htpasswd.load(force=True)
|
||||
assert htpasswd.check_password("new", " test ")
|
||||
assert old_users.union(["new"]) == set(htpasswd.users())
|
||||
|
||||
|
||||
# =====
|
||||
def test_main__set__change_getpass__ok(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore
|
||||
old_users = set(htpasswd.users())
|
||||
if old_users:
|
||||
assert htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
|
||||
mocker.patch.object(getpass, "getpass", (lambda *_, **__: " test "))
|
||||
_run_main(htpasswd, ["set", "admin"])
|
||||
|
||||
htpasswd.load(force=True)
|
||||
assert htpasswd.check_password("admin", " test ")
|
||||
assert old_users == set(htpasswd.users())
|
||||
|
||||
|
||||
def test_main__set__change_getpass__fail(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore
|
||||
old_users = set(htpasswd.users())
|
||||
if old_users:
|
||||
assert htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
|
||||
count = 0
|
||||
|
||||
def fake_getpass(*_: Any, **__: Any) -> str:
|
||||
nonlocal count
|
||||
assert count <= 1
|
||||
if count == 0:
|
||||
passwd = " test "
|
||||
else:
|
||||
passwd = "test "
|
||||
count += 1
|
||||
return passwd
|
||||
|
||||
mocker.patch.object(getpass, "getpass", fake_getpass)
|
||||
with pytest.raises(SystemExit, match="Sorry, passwords do not match"):
|
||||
_run_main(htpasswd, ["set", "admin"])
|
||||
assert count == 2
|
||||
|
||||
htpasswd.load(force=True)
|
||||
assert htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
assert old_users == set(htpasswd.users())
|
||||
|
||||
|
||||
# =====
|
||||
def test_main__del(htpasswd: passlib.apache.HtpasswdFile) -> None:
|
||||
old_users = set(htpasswd.users())
|
||||
|
||||
if old_users:
|
||||
assert htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
|
||||
_run_main(htpasswd, ["del", "admin"])
|
||||
|
||||
htpasswd.load(force=True)
|
||||
assert not htpasswd.check_password("admin", _make_passwd("admin"))
|
||||
assert old_users.difference(["admin"]) == set(htpasswd.users())
|
||||
Loading…
x
Reference in New Issue
Block a user