mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 23:37:18 +00:00
add ability to remove an user
also replace old user by new one before creation
This commit is contained in:
parent
e99c2b0c83
commit
41731ca359
@ -62,7 +62,6 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
_set_check_parser(subparsers)
|
_set_check_parser(subparsers)
|
||||||
_set_clean_parser(subparsers)
|
_set_clean_parser(subparsers)
|
||||||
_set_config_parser(subparsers)
|
_set_config_parser(subparsers)
|
||||||
_set_create_user_parser(subparsers)
|
|
||||||
_set_init_parser(subparsers)
|
_set_init_parser(subparsers)
|
||||||
_set_key_import_parser(subparsers)
|
_set_key_import_parser(subparsers)
|
||||||
_set_rebuild_parser(subparsers)
|
_set_rebuild_parser(subparsers)
|
||||||
@ -76,6 +75,7 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
_set_status_update_parser(subparsers)
|
_set_status_update_parser(subparsers)
|
||||||
_set_sync_parser(subparsers)
|
_set_sync_parser(subparsers)
|
||||||
_set_update_parser(subparsers)
|
_set_update_parser(subparsers)
|
||||||
|
_set_user_parser(subparsers)
|
||||||
_set_web_parser(subparsers)
|
_set_web_parser(subparsers)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
@ -141,31 +141,6 @@ def _set_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_create_user_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|
||||||
"""
|
|
||||||
add parser for create user subcommand
|
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
|
||||||
"""
|
|
||||||
parser = root.add_parser(
|
|
||||||
"create-user",
|
|
||||||
help="create user for web services",
|
|
||||||
description="create user for web services with password and role. In case if password was not entered it will be asked interactively",
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
||||||
parser.add_argument("username", help="username for web service")
|
|
||||||
parser.add_argument("--as-service", help="add user as service user", action="store_true")
|
|
||||||
parser.add_argument("-r", "--role", help="user role", type=UserAccess, choices=UserAccess, default=UserAccess.Read)
|
|
||||||
parser.add_argument("-p", "--password", help="user password")
|
|
||||||
parser.set_defaults(
|
|
||||||
handler=handlers.CreateUser,
|
|
||||||
architecture=[""],
|
|
||||||
lock=None,
|
|
||||||
no_log=True,
|
|
||||||
no_report=True,
|
|
||||||
unsafe=True)
|
|
||||||
return parser
|
|
||||||
|
|
||||||
|
|
||||||
def _set_init_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_init_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for init subcommand
|
add parser for init subcommand
|
||||||
@ -359,6 +334,32 @@ def _set_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_user_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for create user subcommand
|
||||||
|
:param root: subparsers for the commands
|
||||||
|
:return: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser(
|
||||||
|
"user",
|
||||||
|
help="manage users for web services",
|
||||||
|
description="manage users for web services with password and role. In case if password was not entered it will be asked interactively",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
parser.add_argument("username", help="username for web service")
|
||||||
|
parser.add_argument("--as-service", help="add user as service user", action="store_true")
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--access",
|
||||||
|
help="user access level",
|
||||||
|
type=UserAccess,
|
||||||
|
choices=UserAccess,
|
||||||
|
default=UserAccess.Read)
|
||||||
|
parser.add_argument("-p", "--password", help="user password")
|
||||||
|
parser.add_argument("-r", "--remove", help="remove user from configuration", action="store_true")
|
||||||
|
parser.set_defaults(handler=handlers.User, architecture=[""], lock=None, no_log=True, no_report=True, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for web subcommand
|
add parser for web subcommand
|
||||||
|
@ -21,7 +21,6 @@ from ahriman.application.handlers.handler import Handler
|
|||||||
|
|
||||||
from ahriman.application.handlers.add import Add
|
from ahriman.application.handlers.add import Add
|
||||||
from ahriman.application.handlers.clean import Clean
|
from ahriman.application.handlers.clean import Clean
|
||||||
from ahriman.application.handlers.create_user import CreateUser
|
|
||||||
from ahriman.application.handlers.dump import Dump
|
from ahriman.application.handlers.dump import Dump
|
||||||
from ahriman.application.handlers.init import Init
|
from ahriman.application.handlers.init import Init
|
||||||
from ahriman.application.handlers.key_import import KeyImport
|
from ahriman.application.handlers.key_import import KeyImport
|
||||||
@ -36,4 +35,5 @@ from ahriman.application.handlers.status import Status
|
|||||||
from ahriman.application.handlers.status_update import StatusUpdate
|
from ahriman.application.handlers.status_update import StatusUpdate
|
||||||
from ahriman.application.handlers.sync import Sync
|
from ahriman.application.handlers.sync import Sync
|
||||||
from ahriman.application.handlers.update import Update
|
from ahriman.application.handlers.update import Update
|
||||||
|
from ahriman.application.handlers.user import User
|
||||||
from ahriman.application.handlers.web import Web
|
from ahriman.application.handlers.web import Web
|
||||||
|
@ -25,12 +25,13 @@ from typing import Type
|
|||||||
|
|
||||||
from ahriman.application.handlers.handler import Handler
|
from ahriman.application.handlers.handler import Handler
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.models.user import User
|
from ahriman.models.user import User as MUser
|
||||||
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
|
|
||||||
class CreateUser(Handler):
|
class User(Handler):
|
||||||
"""
|
"""
|
||||||
create user handler
|
user management handler
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -43,13 +44,30 @@ class CreateUser(Handler):
|
|||||||
:param configuration: configuration instance
|
:param configuration: configuration instance
|
||||||
:param no_report: force disable reporting
|
:param no_report: force disable reporting
|
||||||
"""
|
"""
|
||||||
salt = CreateUser.get_salt(configuration)
|
salt = User.get_salt(configuration)
|
||||||
user = CreateUser.create_user(args)
|
user = User.create_user(args)
|
||||||
auth_configuration = CreateUser.get_auth_configuration(configuration.include)
|
auth_configuration = User.get_auth_configuration(configuration.include)
|
||||||
CreateUser.create_configuration(auth_configuration, user, salt, args.as_service)
|
|
||||||
|
User.clear_user(auth_configuration, user)
|
||||||
|
if not args.remove:
|
||||||
|
User.create_configuration(auth_configuration, user, salt, args.as_service)
|
||||||
|
User.write_configuration(configuration)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_configuration(configuration: Configuration, user: User, salt: str, as_service_user: bool) -> None:
|
def clear_user(configuration: Configuration, user: MUser) -> None:
|
||||||
|
"""
|
||||||
|
remove user user from configuration file in case if it exists
|
||||||
|
:param configuration: configuration instance
|
||||||
|
:param user: user descriptor
|
||||||
|
"""
|
||||||
|
for role in UserAccess:
|
||||||
|
section = Configuration.section_name("auth", role.value)
|
||||||
|
if not configuration.has_option(section, user.username):
|
||||||
|
continue
|
||||||
|
configuration.remove_option(section, user.username)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_configuration(configuration: Configuration, user: MUser, salt: str, as_service_user: bool) -> None:
|
||||||
"""
|
"""
|
||||||
put new user to configuration
|
put new user to configuration
|
||||||
:param configuration: configuration instance
|
:param configuration: configuration instance
|
||||||
@ -65,19 +83,14 @@ class CreateUser(Handler):
|
|||||||
configuration.set_option("web", "username", user.username)
|
configuration.set_option("web", "username", user.username)
|
||||||
configuration.set_option("web", "password", user.password)
|
configuration.set_option("web", "password", user.password)
|
||||||
|
|
||||||
if configuration.path is None:
|
|
||||||
return
|
|
||||||
with configuration.path.open("w") as ahriman_configuration:
|
|
||||||
configuration.write(ahriman_configuration)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_user(args: argparse.Namespace) -> User:
|
def create_user(args: argparse.Namespace) -> MUser:
|
||||||
"""
|
"""
|
||||||
create user descriptor from arguments
|
create user descriptor from arguments
|
||||||
:param args: command line args
|
:param args: command line args
|
||||||
:return: built user descriptor
|
:return: built user descriptor
|
||||||
"""
|
"""
|
||||||
user = User(args.username, args.password, args.role)
|
user = MUser(args.username, args.password, args.access)
|
||||||
if user.password is None:
|
if user.password is None:
|
||||||
user.password = getpass.getpass()
|
user.password = getpass.getpass()
|
||||||
return user
|
return user
|
||||||
@ -91,7 +104,6 @@ class CreateUser(Handler):
|
|||||||
"""
|
"""
|
||||||
target = include_path / "auth.ini"
|
target = include_path / "auth.ini"
|
||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
if target.is_file(): # load current configuration in case if it exists
|
|
||||||
configuration.load(target)
|
configuration.load(target)
|
||||||
|
|
||||||
return configuration
|
return configuration
|
||||||
@ -107,4 +119,16 @@ class CreateUser(Handler):
|
|||||||
salt = configuration.get("auth", "salt", fallback=None)
|
salt = configuration.get("auth", "salt", fallback=None)
|
||||||
if salt:
|
if salt:
|
||||||
return salt
|
return salt
|
||||||
return User.generate_password(salt_length)
|
return MUser.generate_password(salt_length)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def write_configuration(configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
write configuration file
|
||||||
|
:param configuration: configuration instance
|
||||||
|
"""
|
||||||
|
if configuration.path is None:
|
||||||
|
return # should never happen actually
|
||||||
|
with configuration.path.open("w") as ahriman_configuration:
|
||||||
|
configuration.write(ahriman_configuration)
|
||||||
|
configuration.path.chmod(0o600)
|
@ -1,164 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from pytest_mock import MockerFixture
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from ahriman.application.handlers import CreateUser
|
|
||||||
from ahriman.core.configuration import Configuration
|
|
||||||
from ahriman.models.user import User
|
|
||||||
from ahriman.models.user_access import UserAccess
|
|
||||||
|
|
||||||
|
|
||||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|
||||||
"""
|
|
||||||
default arguments for these test cases
|
|
||||||
:param args: command line arguments fixture
|
|
||||||
:return: generated arguments for these test cases
|
|
||||||
"""
|
|
||||||
args.username = "user"
|
|
||||||
args.password = "pa55w0rd"
|
|
||||||
args.role = UserAccess.Read
|
|
||||||
args.as_service = False
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must run command
|
|
||||||
"""
|
|
||||||
args = _default_args(args)
|
|
||||||
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.CreateUser.get_auth_configuration")
|
|
||||||
create_configuration_mock = mocker.patch("ahriman.application.handlers.CreateUser.create_configuration")
|
|
||||||
create_user = mocker.patch("ahriman.application.handlers.CreateUser.create_user")
|
|
||||||
get_salt_mock = mocker.patch("ahriman.application.handlers.CreateUser.get_salt")
|
|
||||||
|
|
||||||
CreateUser.run(args, "x86_64", configuration, True)
|
|
||||||
get_auth_configuration_mock.assert_called_once()
|
|
||||||
create_configuration_mock.assert_called_once()
|
|
||||||
create_user.assert_called_once()
|
|
||||||
get_salt_mock.assert_called_once()
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_configuration(configuration: Configuration, user: User, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must correctly create configuration file
|
|
||||||
"""
|
|
||||||
section = Configuration.section_name("auth", user.access.value)
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
set_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
|
|
||||||
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
|
||||||
|
|
||||||
CreateUser.create_configuration(configuration, user, "salt", False)
|
|
||||||
write_mock.assert_called_once()
|
|
||||||
set_mock.assert_has_calls([
|
|
||||||
mock.call("auth", "salt", pytest.helpers.anyvar(str)),
|
|
||||||
mock.call(section, user.username, pytest.helpers.anyvar(str))
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_configuration_not_loaded(configuration: Configuration, user: User, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must do nothing in case if configuration is not loaded
|
|
||||||
"""
|
|
||||||
configuration.path = None
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
|
||||||
|
|
||||||
CreateUser.create_configuration(configuration, user, "salt", False)
|
|
||||||
write_mock.assert_not_called()
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_configuration_user_exists(configuration: Configuration, user: User, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must correctly update configuration file if user already exists
|
|
||||||
"""
|
|
||||||
section = Configuration.section_name("auth", user.access.value)
|
|
||||||
configuration.set_option(section, user.username, "")
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
mocker.patch("ahriman.core.configuration.Configuration.write")
|
|
||||||
|
|
||||||
CreateUser.create_configuration(configuration, user, "salt", False)
|
|
||||||
generated = User.from_option(user.username, configuration.get(section, user.username))
|
|
||||||
assert generated.check_credentials(user.password, configuration.get("auth", "salt"))
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_configuration_with_plain_password(
|
|
||||||
configuration: Configuration,
|
|
||||||
user: User,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must set plain text password and user for the service
|
|
||||||
"""
|
|
||||||
section = Configuration.section_name("auth", user.access.value)
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
mocker.patch("ahriman.core.configuration.Configuration.write")
|
|
||||||
|
|
||||||
CreateUser.create_configuration(configuration, user, "salt", True)
|
|
||||||
|
|
||||||
generated = User.from_option(user.username, configuration.get(section, user.username))
|
|
||||||
service = User.from_option(configuration.get("web", "username"), configuration.get("web", "password"))
|
|
||||||
assert generated.username == service.username
|
|
||||||
assert generated.check_credentials(service.password, configuration.get("auth", "salt"))
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_user(args: argparse.Namespace, user: User) -> None:
|
|
||||||
"""
|
|
||||||
must create user
|
|
||||||
"""
|
|
||||||
args = _default_args(args)
|
|
||||||
generated = CreateUser.create_user(args)
|
|
||||||
assert generated.username == user.username
|
|
||||||
assert generated.access == user.access
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_user_getpass(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must create user and get password from command line
|
|
||||||
"""
|
|
||||||
args = _default_args(args)
|
|
||||||
args.password = None
|
|
||||||
|
|
||||||
getpass_mock = mocker.patch("getpass.getpass", return_value="password")
|
|
||||||
generated = CreateUser.create_user(args)
|
|
||||||
|
|
||||||
getpass_mock.assert_called_once()
|
|
||||||
assert generated.password == "password"
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_salt_read(configuration: Configuration) -> None:
|
|
||||||
"""
|
|
||||||
must read salt from configuration
|
|
||||||
"""
|
|
||||||
assert CreateUser.get_salt(configuration) == "salt"
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_salt_generate(configuration: Configuration) -> None:
|
|
||||||
"""
|
|
||||||
must generate salt if it does not exist
|
|
||||||
"""
|
|
||||||
configuration.remove_option("auth", "salt")
|
|
||||||
|
|
||||||
salt = CreateUser.get_salt(configuration, 16)
|
|
||||||
assert salt
|
|
||||||
assert len(salt) == 16
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_auth_configuration() -> None:
|
|
||||||
"""
|
|
||||||
must load empty configuration
|
|
||||||
"""
|
|
||||||
assert CreateUser.get_auth_configuration(Path("path"))
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_auth_configuration_exists(mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must load configuration from filesystem
|
|
||||||
"""
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
|
||||||
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
|
||||||
|
|
||||||
CreateUser.get_auth_configuration(Path("path"))
|
|
||||||
read_mock.assert_called_once()
|
|
224
tests/ahriman/application/handlers/test_handler_user.py
Normal file
224
tests/ahriman/application/handlers/test_handler_user.py
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
import argparse
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from ahriman.application.handlers import User
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.models.user import User as MUser
|
||||||
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
|
|
||||||
|
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||||
|
"""
|
||||||
|
default arguments for these test cases
|
||||||
|
:param args: command line arguments fixture
|
||||||
|
:return: generated arguments for these test cases
|
||||||
|
"""
|
||||||
|
args.username = "user"
|
||||||
|
args.password = "pa55w0rd"
|
||||||
|
args.access = UserAccess.Read
|
||||||
|
args.as_service = False
|
||||||
|
args.remove = False
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must run command
|
||||||
|
"""
|
||||||
|
args = _default_args(args)
|
||||||
|
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.User.get_auth_configuration")
|
||||||
|
create_configuration_mock = mocker.patch("ahriman.application.handlers.User.create_configuration")
|
||||||
|
write_configuration_mock = mocker.patch("ahriman.application.handlers.User.write_configuration")
|
||||||
|
create_user = mocker.patch("ahriman.application.handlers.User.create_user")
|
||||||
|
get_salt_mock = mocker.patch("ahriman.application.handlers.User.get_salt")
|
||||||
|
|
||||||
|
User.run(args, "x86_64", configuration, True)
|
||||||
|
get_auth_configuration_mock.assert_called_once()
|
||||||
|
create_configuration_mock.assert_called_once()
|
||||||
|
create_user.assert_called_once()
|
||||||
|
get_salt_mock.assert_called_once()
|
||||||
|
write_configuration_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_remove(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must remove user if remove flag supplied
|
||||||
|
"""
|
||||||
|
args = _default_args(args)
|
||||||
|
args.remove = True
|
||||||
|
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.User.get_auth_configuration")
|
||||||
|
create_configuration_mock = mocker.patch("ahriman.application.handlers.User.create_configuration")
|
||||||
|
write_configuration_mock = mocker.patch("ahriman.application.handlers.User.write_configuration")
|
||||||
|
|
||||||
|
User.run(args, "x86_64", configuration, True)
|
||||||
|
get_auth_configuration_mock.assert_called_once()
|
||||||
|
create_configuration_mock.assert_not_called()
|
||||||
|
write_configuration_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_clear_user(configuration: Configuration, user: MUser) -> None:
|
||||||
|
"""
|
||||||
|
must clear user from configuration
|
||||||
|
"""
|
||||||
|
section = Configuration.section_name("auth", user.access.value)
|
||||||
|
configuration.set_option(section, user.username, user.password)
|
||||||
|
|
||||||
|
User.clear_user(configuration, user)
|
||||||
|
assert configuration.get(section, user.username, fallback=None) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_clear_user_multiple_sections(configuration: Configuration, user: MUser) -> None:
|
||||||
|
"""
|
||||||
|
must clear user from configuration from all sections
|
||||||
|
"""
|
||||||
|
for role in UserAccess:
|
||||||
|
section = Configuration.section_name("auth", role.value)
|
||||||
|
configuration.set_option(section, user.username, user.password)
|
||||||
|
|
||||||
|
User.clear_user(configuration, user)
|
||||||
|
for role in UserAccess:
|
||||||
|
section = Configuration.section_name("auth", role.value)
|
||||||
|
assert configuration.get(section, user.username, fallback=None) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_configuration(configuration: Configuration, user: MUser, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must correctly create configuration file
|
||||||
|
"""
|
||||||
|
section = Configuration.section_name("auth", user.access.value)
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
set_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
|
||||||
|
|
||||||
|
User.create_configuration(configuration, user, "salt", False)
|
||||||
|
set_mock.assert_has_calls([
|
||||||
|
mock.call("auth", "salt", pytest.helpers.anyvar(str)),
|
||||||
|
mock.call(section, user.username, pytest.helpers.anyvar(str))
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_configuration_user_exists(configuration: Configuration, user: MUser, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must correctly update configuration file if user already exists
|
||||||
|
"""
|
||||||
|
section = Configuration.section_name("auth", user.access.value)
|
||||||
|
configuration.set_option(section, user.username, "")
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
|
||||||
|
User.create_configuration(configuration, user, "salt", False)
|
||||||
|
generated = MUser.from_option(user.username, configuration.get(section, user.username))
|
||||||
|
assert generated.check_credentials(user.password, configuration.get("auth", "salt"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_configuration_with_plain_password(
|
||||||
|
configuration: Configuration,
|
||||||
|
user: MUser,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must set plain text password and user for the service
|
||||||
|
"""
|
||||||
|
section = Configuration.section_name("auth", user.access.value)
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
|
||||||
|
User.create_configuration(configuration, user, "salt", True)
|
||||||
|
|
||||||
|
generated = MUser.from_option(user.username, configuration.get(section, user.username))
|
||||||
|
service = MUser.from_option(configuration.get("web", "username"), configuration.get("web", "password"))
|
||||||
|
assert generated.username == service.username
|
||||||
|
assert generated.check_credentials(service.password, configuration.get("auth", "salt"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_user(args: argparse.Namespace, user: MUser) -> None:
|
||||||
|
"""
|
||||||
|
must create user
|
||||||
|
"""
|
||||||
|
args = _default_args(args)
|
||||||
|
generated = User.create_user(args)
|
||||||
|
assert generated.username == user.username
|
||||||
|
assert generated.access == user.access
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_user_getpass(args: argparse.Namespace, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must create user and get password from command line
|
||||||
|
"""
|
||||||
|
args = _default_args(args)
|
||||||
|
args.password = None
|
||||||
|
|
||||||
|
getpass_mock = mocker.patch("getpass.getpass", return_value="password")
|
||||||
|
generated = User.create_user(args)
|
||||||
|
|
||||||
|
getpass_mock.assert_called_once()
|
||||||
|
assert generated.password == "password"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_salt_read(configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
must read salt from configuration
|
||||||
|
"""
|
||||||
|
assert User.get_salt(configuration) == "salt"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_salt_generate(configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
must generate salt if it does not exist
|
||||||
|
"""
|
||||||
|
configuration.remove_option("auth", "salt")
|
||||||
|
|
||||||
|
salt = User.get_salt(configuration, 16)
|
||||||
|
assert salt
|
||||||
|
assert len(salt) == 16
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_auth_configuration_exists(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must load configuration from filesystem
|
||||||
|
"""
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||||
|
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
||||||
|
|
||||||
|
assert User.get_auth_configuration(Path("path"))
|
||||||
|
read_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_auth_configuration_not_exists(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must try to load configuration from filesystem
|
||||||
|
"""
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||||
|
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
|
||||||
|
|
||||||
|
assert User.get_auth_configuration(Path("path"))
|
||||||
|
read_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_configuration(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must write configuration
|
||||||
|
"""
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||||
|
chmod_mock = mocker.patch("pathlib.Path.chmod")
|
||||||
|
|
||||||
|
User.write_configuration(configuration)
|
||||||
|
write_mock.assert_called_once()
|
||||||
|
chmod_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_configuration_not_loaded(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must do nothing in case if configuration is not loaded
|
||||||
|
"""
|
||||||
|
configuration.path = None
|
||||||
|
mocker.patch("pathlib.Path.open")
|
||||||
|
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
|
||||||
|
chmod_mock = mocker.patch("pathlib.Path.chmod")
|
||||||
|
|
||||||
|
User.write_configuration(configuration)
|
||||||
|
write_mock.assert_not_called()
|
||||||
|
chmod_mock.assert_not_called()
|
@ -84,28 +84,6 @@ def test_subparsers_config(parser: argparse.ArgumentParser) -> None:
|
|||||||
assert args.unsafe
|
assert args.unsafe
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_create_user(parser: argparse.ArgumentParser) -> None:
|
|
||||||
"""
|
|
||||||
create-user command must imply architecture, lock, no-log, no-report and unsafe
|
|
||||||
"""
|
|
||||||
args = parser.parse_args(["create-user", "username"])
|
|
||||||
assert args.architecture == [""]
|
|
||||||
assert args.lock is None
|
|
||||||
assert args.no_log
|
|
||||||
assert args.no_report
|
|
||||||
assert args.unsafe
|
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_create_user_option_role(parser: argparse.ArgumentParser) -> None:
|
|
||||||
"""
|
|
||||||
create-user command must convert role option to useraccess instance
|
|
||||||
"""
|
|
||||||
args = parser.parse_args(["create-user", "username"])
|
|
||||||
assert isinstance(args.role, UserAccess)
|
|
||||||
args = parser.parse_args(["create-user", "username", "--role", "write"])
|
|
||||||
assert isinstance(args.role, UserAccess)
|
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_init(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_init(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
init command must imply no_report
|
init command must imply no_report
|
||||||
@ -258,6 +236,28 @@ def test_subparsers_update(parser: argparse.ArgumentParser) -> None:
|
|||||||
assert args.architecture == []
|
assert args.architecture == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_user(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
user command must imply architecture, lock, no-log, no-report and unsafe
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["user", "username"])
|
||||||
|
assert args.architecture == [""]
|
||||||
|
assert args.lock is None
|
||||||
|
assert args.no_log
|
||||||
|
assert args.no_report
|
||||||
|
assert args.unsafe
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_user_option_role(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
user command must convert role option to useraccess instance
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["user", "username"])
|
||||||
|
assert isinstance(args.access, UserAccess)
|
||||||
|
args = parser.parse_args(["user", "username", "--access", "write"])
|
||||||
|
assert isinstance(args.access, UserAccess)
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_web(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_web(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
web command must imply lock, no_report and parser
|
web command must imply lock, no_report and parser
|
||||||
|
Loading…
Reference in New Issue
Block a user