summaryrefslogtreecommitdiff
path: root/testenv/tests/apps/kvmd/test_auth.py
blob: fca156adcd82765420c1eeaf74f1a80556dcf978 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# ========================================================================== #
#                                                                            #
#    KVMD - The main Pi-KVM daemon.                                          #
#                                                                            #
#    Copyright (C) 2018  Maxim Devaev <[email protected]>                    #
#                                                                            #
#    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 contextlib

from typing import List
from typing import Dict
from typing import AsyncGenerator
from typing import Optional

import passlib.apache

import pytest

from kvmd.yamlconf import make_config

from kvmd.apps.kvmd.auth import AuthManager

from kvmd.plugins.auth import get_auth_service_class


# =====
def _make_service_kwargs(path: str) -> Dict:
    cls = get_auth_service_class("htpasswd")
    scheme = cls.get_plugin_options()
    return make_config({"file": path}, scheme)._unpack()  # pylint: disable=protected-access


@contextlib.asynccontextmanager
async def _get_configured_manager(
    internal_path: str,
    external_path: str="",
    force_internal_users: Optional[List[str]]=None,
) -> AsyncGenerator[AuthManager, None]:

    manager = AuthManager(
        internal_type="htpasswd",
        internal_kwargs=_make_service_kwargs(internal_path),
        external_type=("htpasswd" if external_path else ""),
        external_kwargs=(_make_service_kwargs(external_path) if external_path else {}),
        force_internal_users=(force_internal_users or []),
    )

    try:
        yield manager
    finally:
        await manager.cleanup()


# =====
@pytest.mark.asyncio
async def test_ok__internal(tmpdir) -> None:  # type: ignore
    path = os.path.abspath(str(tmpdir.join("htpasswd")))

    htpasswd = passlib.apache.HtpasswdFile(path, new=True)
    htpasswd.set_password("admin", "pass")
    htpasswd.save()

    async with _get_configured_manager(path) as manager:
        assert manager.check("xxx") is None
        manager.logout("xxx")

        assert (await manager.login("user", "foo")) is None
        assert (await manager.login("admin", "foo")) is None
        assert (await manager.login("user", "pass")) is None

        token = await manager.login("admin", "pass")
        assert isinstance(token, str)
        assert len(token) == 64

        again = await manager.login("admin", "pass")
        assert token == again

        assert manager.check(token) == "admin"
        manager.logout(token)
        assert manager.check(token) is None

        again = await manager.login("admin", "pass")
        assert token != again


@pytest.mark.asyncio
async def test_ok__external(tmpdir) -> None:  # type: ignore
    path1 = os.path.abspath(str(tmpdir.join("htpasswd1")))
    path2 = os.path.abspath(str(tmpdir.join("htpasswd2")))

    htpasswd1 = passlib.apache.HtpasswdFile(path1, new=True)
    htpasswd1.set_password("admin", "pass1")
    htpasswd1.set_password("local", "foobar")
    htpasswd1.save()

    htpasswd2 = passlib.apache.HtpasswdFile(path2, new=True)
    htpasswd2.set_password("admin", "pass2")
    htpasswd2.set_password("user", "foobar")
    htpasswd2.save()

    async with _get_configured_manager(path1, path2, ["admin"]) as manager:
        assert (await manager.login("local", "foobar")) is None
        assert (await manager.login("admin", "pass2")) is None

        token = await manager.login("admin", "pass1")
        assert token is not None

        assert manager.check(token) == "admin"
        manager.logout(token)
        assert manager.check(token) is None

        token = await manager.login("user", "foobar")
        assert token is not None

        assert manager.check(token) == "user"
        manager.logout(token)
        assert manager.check(token) is None