Skip to content

Commit

Permalink
refactor: rename 'validate' in 'check_network_config'
Browse files Browse the repository at this point in the history
  • Loading branch information
azmeuk committed Feb 2, 2025
1 parent 9e48c9c commit 1446485
Show file tree
Hide file tree
Showing 12 changed files with 41 additions and 141 deletions.
6 changes: 3 additions & 3 deletions canaille/app/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ def dump(path: Path | None):
@with_appcontext
@with_backendcontext
def check():
"""Test the configuration file.
"""Test the network connections defined in the configuration file.
Attempt to reach the database and the SMTP server with the provided
credentials.
"""
from canaille.app.configuration import ConfigurationException
from canaille.app.configuration import validate
from canaille.app.configuration import check_network_config

try:
validate(current_app.config, validate_remote=True)
check_network_config(current_app.config)
except ConfigurationException as exc:
print(exc)
sys.exit(1)
Expand Down
35 changes: 6 additions & 29 deletions canaille/app/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import socket
import textwrap

from flask import current_app
from pydantic import BaseModel as PydanticBaseModel
from pydantic import ValidationError
from pydantic import create_model
Expand Down Expand Up @@ -204,39 +203,17 @@ def setup_config(app, config=None, env_file=None, env_prefix=""):
return True


def validate(config, validate_remote=False):
validate_keypair(config.get("CANAILLE_OIDC"))
if not validate_remote:
return

def check_network_config(config):
from canaille.backends import Backend

Backend.instance.validate(config)
Backend.instance.check_network_config(config)
if smtp_config := config["CANAILLE"]["SMTP"]:
validate_smtp_configuration(smtp_config)
test_smtp_configuration(smtp_config)
if smpp_config := config["CANAILLE"]["SMPP"]:
validate_smpp_configuration(smpp_config)


def validate_keypair(config):
if (
config
and config["JWT"]
and not config["JWT"]["PUBLIC_KEY"]
and not current_app.debug
):
raise ConfigurationException("No public key has been set")

if (
config
and config["JWT"]
and not config["JWT"]["PRIVATE_KEY"]
and not current_app.debug
):
raise ConfigurationException("No private key has been set")
test_smpp_configuration(smpp_config)


def validate_smtp_configuration(config):
def test_smtp_configuration(config):
host = config["HOST"]
port = config["PORT"]
try:
Expand All @@ -263,7 +240,7 @@ def validate_smtp_configuration(config):
raise ConfigurationException(exc) from exc


def validate_smpp_configuration(config):
def test_smpp_configuration(config):
import smpplib

host = config["HOST"]
Expand Down
10 changes: 3 additions & 7 deletions canaille/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def teardown(self):
"""Is called after each http request, it should close the connections to the backend."""

@classmethod
def validate(cls, config):
"""Validate the config part dedicated to the backend.
def check_network_config(cls, config):
"""check_network_config the config part dedicated to the backend.
It should raise :class:`~canaille.configuration.ConfigurationError` when
errors are met.
Expand Down Expand Up @@ -179,11 +179,7 @@ def register_models(self):
from canaille.app import models

module = ".".join(self.__class__.__module__.split(".")[:-1] + ["models"])
try:
backend_models = importlib.import_module(module)
except ModuleNotFoundError:
return

backend_models = importlib.import_module(module)
model_names = [
"AuthorizationCode",
"Client",
Expand Down
2 changes: 1 addition & 1 deletion canaille/backends/ldap/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def teardown(self):
self._connection = None

@classmethod
def validate(cls, config):
def check_network_config(cls, config):
from canaille.app import models

with cls(config).session():
Expand Down
2 changes: 1 addition & 1 deletion canaille/backends/memory/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def teardown(self):
pass

@classmethod
def validate(cls, config):
def check_network_config(cls, config):
pass

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion canaille/backends/sql/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def teardown(self):
pass

@classmethod
def validate(cls, config):
def check_network_config(cls, config):
pass

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion tests/app/commands/test_config_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def test_check_command(testclient, mock_smpp):
runner = testclient.app.test_cli_runner()
res = runner.invoke(cli, ["config", "check"])
res = runner.invoke(cli, ["config", "check"], catch_exceptions=False)
assert res.exit_code == 0, res.stdout


Expand Down
56 changes: 17 additions & 39 deletions tests/app/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

from canaille import create_app
from canaille.app.configuration import ConfigurationException
from canaille.app.configuration import check_network_config
from canaille.app.configuration import export_config
from canaille.app.configuration import sanitize_rst_text
from canaille.app.configuration import settings_factory
from canaille.app.configuration import validate


def test_configuration_secrets_directory(tmp_path, backend, configuration):
Expand Down Expand Up @@ -173,7 +173,7 @@ def test_smtp_connection_remote_smtp_unreachable(testclient, backend, configurat
ConfigurationException,
match=r"Could not connect to the SMTP server",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_smtp_connection_remote_smtp_wrong_credentials(
Expand All @@ -186,7 +186,7 @@ def test_smtp_connection_remote_smtp_wrong_credentials(
ConfigurationException,
match=r"SMTP authentication failed with user",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_smtp_connection_remote_smtp_no_credentials(
Expand All @@ -196,7 +196,7 @@ def test_smtp_connection_remote_smtp_no_credentials(
del configuration["CANAILLE"]["SMTP"]["PASSWORD"]
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_smtp_bad_tls(testclient, backend, smtpd, configuration):
Expand All @@ -207,7 +207,7 @@ def test_smtp_bad_tls(testclient, backend, smtpd, configuration):
ConfigurationException,
match=r"SMTP AUTH extension not supported by server",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


@pytest.fixture
Expand All @@ -230,90 +230,68 @@ def test_theme(testclient, themed_testclient, backend):


def test_invalid_theme(configuration, backend):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()

validate(config_dict, validate_remote=False)

with pytest.raises(
ValidationError,
match=r"Path does not point to a directory",
):
configuration["CANAILLE"]["THEME"] = "invalid"
config_obj = settings_factory(configuration)
settings_factory(configuration)

with pytest.raises(
ValidationError,
match=r"Path does not point to a directory",
):
configuration["CANAILLE"]["THEME"] = "/path/to/invalid"
config_obj = settings_factory(configuration)
settings_factory(configuration)


def test_enable_password_compromission_check_with_and_without_admin_email(
configuration, backend
):
configuration["CANAILLE"]["ENABLE_PASSWORD_COMPROMISSION_CHECK"] = False
configuration["CANAILLE"]["ADMIN_EMAIL"] = None
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()
validate(config_dict, validate_remote=False)
settings_factory(configuration)

configuration["CANAILLE"]["ENABLE_PASSWORD_COMPROMISSION_CHECK"] = True
configuration["CANAILLE"]["ADMIN_EMAIL"] = "[email protected]"
config_obj = settings_factory(configuration)
settings_factory(configuration)

with pytest.raises(
ValidationError,
match=r"You must set an administration email if you want to check if users' passwords are compromised.",
):
configuration["CANAILLE"]["ENABLE_PASSWORD_COMPROMISSION_CHECK"] = True
configuration["CANAILLE"]["ADMIN_EMAIL"] = None
config_obj = settings_factory(configuration)
settings_factory(configuration)


def test_invalid_otp_option(configuration, backend):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()

validate(config_dict, validate_remote=False)

with pytest.raises(
ValidationError,
match=r"Input should be 'TOTP' or 'HOTP'",
):
configuration["CANAILLE"]["OTP_METHOD"] = "invalid"
config_obj = settings_factory(configuration)
settings_factory(configuration)


def test_email_otp_without_smtp(configuration, backend):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()

validate(config_dict, validate_remote=False)

with pytest.raises(
ValidationError,
match=r"Cannot activate email one-time password authentication without SMTP",
):
configuration["CANAILLE"]["SMTP"] = None
configuration["CANAILLE"]["EMAIL_OTP"] = True
config_obj = settings_factory(configuration)
settings_factory(configuration)


def test_sms_otp_without_smpp(configuration, backend):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()

validate(config_dict, validate_remote=False)

with pytest.raises(
ValidationError,
match=r"Cannot activate sms one-time password authentication without SMPP",
):
configuration["CANAILLE"]["SMPP"] = None
configuration["CANAILLE"]["SMS_OTP"] = True
config_obj = settings_factory(configuration)
settings_factory(configuration)


def test_smpp_connection_remote_smpp_unreachable(testclient, backend, configuration):
Expand All @@ -329,15 +307,15 @@ def test_smpp_connection_remote_smpp_unreachable(testclient, backend, configurat
ConfigurationException,
match=r"Could not connect to the SMPP server 'invalid-smpp.com' on port '2775'",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_validate_without_smpp(configuration, backend, mock_smpp):
def test_check_network_config_without_smpp(configuration, backend, mock_smpp):
configuration["CANAILLE"]["SMPP"] = None
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()

validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_smpp_connection_remote_smpp_no_credentials(
Expand All @@ -347,7 +325,7 @@ def test_smpp_connection_remote_smpp_no_credentials(
del configuration["CANAILLE"]["SMPP"]["PASSWORD"]
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_no_secret_key(configuration, caplog):
Expand Down
4 changes: 2 additions & 2 deletions tests/backends/ldap/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def slapd_server():
def test_setup_ldap_tree(slapd_server, configuration):
output = slapd_server.slapcat().stdout.decode("utf-8")
assert "dn: ou=tokens,ou=oauth,dc=example,dc=org" not in output
testclient = TestApp(create_app(configuration, validate=False))
testclient = TestApp(create_app(configuration))
runner = testclient.app.test_cli_runner()
res = runner.invoke(cli, ["install"])
assert res.exit_code == 0, res.stdout
Expand Down Expand Up @@ -125,7 +125,7 @@ def test_install_schemas_command(configuration, slapd_server):
with LDAPBackend(config_dict).session():
assert "oauthClient" not in LDAPObject.ldap_object_classes(force=True)

testclient = TestApp(create_app(configuration, validate=False))
testclient = TestApp(create_app(configuration))
runner = testclient.app.test_cli_runner()
res = runner.invoke(cli, ["install"])
assert res.exit_code == 0, res.stdout
Expand Down
18 changes: 6 additions & 12 deletions tests/backends/ldap/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from canaille.app import models
from canaille.app.configuration import ConfigurationException
from canaille.app.configuration import check_network_config
from canaille.app.configuration import settings_factory
from canaille.app.configuration import validate
from canaille.backends.ldap.ldapobject import LDAPObject
from canaille.backends.ldap.ldapobject import python_attrs_to_ldap
from canaille.backends.ldap.utils import Syntax
Expand Down Expand Up @@ -180,16 +180,10 @@ def test_operational_attribute_conversion(backend):
}


def test_ldap_connection_no_remote(testclient, configuration):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()
validate(config_dict)


def test_ldap_connection_remote(testclient, configuration, backend, mock_smpp):
config_obj = settings_factory(configuration)
config_dict = config_obj.model_dump()
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_ldap_connection_remote_ldap_unreachable(testclient, configuration):
Expand All @@ -201,7 +195,7 @@ def test_ldap_connection_remote_ldap_unreachable(testclient, configuration):
ConfigurationException,
match=r"Could not connect to the LDAP server",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_ldap_connection_remote_ldap_wrong_credentials(testclient, configuration):
Expand All @@ -213,7 +207,7 @@ def test_ldap_connection_remote_ldap_wrong_credentials(testclient, configuration
ConfigurationException,
match=r"LDAP authentication failed with user",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_ldap_cannot_create_users(testclient, configuration, backend):
Expand All @@ -230,7 +224,7 @@ def fake_init(*args, **kwarg):
ConfigurationException,
match=r"cannot create users at",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_ldap_cannot_create_groups(testclient, configuration, backend):
Expand All @@ -247,7 +241,7 @@ def fake_init(*args, **kwarg):
ConfigurationException,
match=r"cannot create groups at",
):
validate(config_dict, validate_remote=True)
check_network_config(config_dict)


def test_login_placeholder(testclient):
Expand Down
Loading

0 comments on commit 1446485

Please sign in to comment.