implemented a function that checks some parts of the configuration

This commit is contained in:
Éloi Rivard 2021-10-12 20:36:31 +02:00 committed by Éloi Rivard
parent 30e071dcaf
commit d0b4121945
6 changed files with 152 additions and 84 deletions

View file

@ -1,3 +1,5 @@
import ldap
import smtplib
import os import os
from cryptography.hazmat.primitives import serialization as crypto_serialization from cryptography.hazmat.primitives import serialization as crypto_serialization
@ -12,6 +14,28 @@ def validate(config, validate_remote=False):
if not os.path.exists(config["JWT"]["PRIVATE_KEY"]): if not os.path.exists(config["JWT"]["PRIVATE_KEY"]):
raise Exception(f'Private key does not exist {config["JWT"]["PRIVATE_KEY"]}') raise Exception(f'Private key does not exist {config["JWT"]["PRIVATE_KEY"]}')
if not validate_remote:
return
conn = ldap.initialize(config["LDAP"]["URI"])
if config["LDAP"].get("TIMEOUT"):
conn.set_option(ldap.OPT_NETWORK_TIMEOUT, config["LDAP"]["TIMEOUT"])
conn.simple_bind_s(config["LDAP"]["BIND_DN"], config["LDAP"]["BIND_PW"])
conn.unbind_s()
with smtplib.SMTP(
host=config["SMTP"]["HOST"],
port=config["SMTP"]["PORT"],
) as smtp:
if config["SMTP"].get("TLS"):
smtp.starttls()
if config["SMTP"].get("LOGIN"):
smtp.login(
user=config["SMTP"]["LOGIN"],
password=config["SMTP"].get("PASSWORD"),
)
def setup_dev_keypair(config): def setup_dev_keypair(config):
if os.path.exists(config["JWT"]["PUBLIC_KEY"]) or os.path.exists( if os.path.exists(config["JWT"]["PUBLIC_KEY"]) or os.path.exists(

View file

@ -60,6 +60,7 @@ deps =
pdbpp pdbpp
pytest pytest
slapd slapd
smtpdfix
[testenv:doc] [testenv:doc]
deps = deps =
@ -77,6 +78,7 @@ deps =
pytest pytest
pytest-coverage pytest-coverage
slapd slapd
smtpdfix
commands = commands =
{envbindir}/pytest --cov {posargs} {envbindir}/pytest --cov {posargs}

View file

@ -121,12 +121,10 @@ def slapd_connection(slapd_server):
@pytest.fixture @pytest.fixture
def app(slapd_server, keypair_path): def configuration(slapd_server, smtpd, keypair_path):
os.environ["AUTHLIB_INSECURE_TRANSPORT"] = "true" smtpd.config.use_starttls = True
private_key_path, public_key_path = keypair_path private_key_path, public_key_path = keypair_path
return {
app = create_app(
{
"SECRET_KEY": gen_salt(24), "SECRET_KEY": gen_salt(24),
"OAUTH2_METADATA_FILE": "canaille/conf/oauth-authorization-server.sample.json", "OAUTH2_METADATA_FILE": "canaille/conf/oauth-authorization-server.sample.json",
"OIDC_METADATA_FILE": "canaille/conf/openid-configuration.sample.json", "OIDC_METADATA_FILE": "canaille/conf/openid-configuration.sample.json",
@ -174,15 +172,20 @@ def app(slapd_server, keypair_path):
}, },
}, },
"SMTP": { "SMTP": {
"HOST": "localhost", "HOST": smtpd.hostname,
"PORT": 25, "PORT": smtpd.port,
"TLS": True, "TLS": True,
"LOGIN": "smtp_login", "LOGIN": smtpd.config.login_username,
"PASSWORD": "smtp_password", "PASSWORD": smtpd.config.login_password,
"FROM_ADDR": "admin@mydomain.tld", "FROM_ADDR": "admin@mydomain.tld",
}, },
} }
)
@pytest.fixture
def app(configuration):
os.environ["AUTHLIB_INSECURE_TRANSPORT"] = "true"
app = create_app(configuration)
return app return app
@ -346,14 +349,21 @@ def logged_moderator(moderator, testclient):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def cleanups(slapd_connection): def cleanups(slapd_connection):
yield yield
try:
for consent in Consent.filter(conn=slapd_connection): for consent in Consent.filter(conn=slapd_connection):
consent.delete(conn=slapd_connection) consent.delete(conn=slapd_connection)
except Exception:
pass
@pytest.fixture @pytest.fixture
def foo_group(app, user, slapd_connection): def foo_group(app, user, slapd_connection):
Group.ocs_by_name(slapd_connection) Group.ocs_by_name(slapd_connection)
g = Group(objectClass=["groupOfNames"], member=[user.dn], cn="foo",) g = Group(
objectClass=["groupOfNames"],
member=[user.dn],
cn="foo",
)
g.save(slapd_connection) g.save(slapd_connection)
with app.app_context(): with app.app_context():
user.load_groups(conn=slapd_connection) user.load_groups(conn=slapd_connection)
@ -365,7 +375,11 @@ def foo_group(app, user, slapd_connection):
@pytest.fixture @pytest.fixture
def bar_group(app, admin, slapd_connection): def bar_group(app, admin, slapd_connection):
Group.ocs_by_name(slapd_connection) Group.ocs_by_name(slapd_connection)
g = Group(objectClass=["groupOfNames"], member=[admin.dn], cn="bar",) g = Group(
objectClass=["groupOfNames"],
member=[admin.dn],
cn="bar",
)
g.save(slapd_connection) g.save(slapd_connection)
with app.app_context(): with app.app_context():
admin.load_groups(conn=slapd_connection) admin.load_groups(conn=slapd_connection)

View file

@ -0,0 +1,37 @@
import ldap
import pytest
import smtplib
import socket
from canaille.configuration import validate
def test_ldap_connection_no_remote(configuration):
validate(configuration)
def test_ldap_connection_remote(configuration):
validate(configuration, validate_remote=True)
def test_ldap_connection_remote_ldap_unreachable(configuration):
configuration["LDAP"]["URI"] = "ldap://invalid-ldap.com"
with pytest.raises(ldap.SERVER_DOWN):
validate(configuration, validate_remote=True)
def test_ldap_connection_remote_ldap_wrong_credentials(configuration):
configuration["LDAP"]["BIND_PW"] = "invalid-password"
with pytest.raises(ldap.INVALID_CREDENTIALS):
validate(configuration, validate_remote=True)
def test_smtp_connection_remote_smtp_unreachable(configuration):
configuration["SMTP"]["HOST"] = "smtp://invalid-smtp.com"
with pytest.raises(socket.gaierror):
validate(configuration, validate_remote=True)
def test_smtp_connection_remote_smtp_wrong_credentials(configuration):
configuration["SMTP"]["PASSWORD"] = "invalid-password"
with pytest.raises(smtplib.SMTPAuthenticationError):
validate(configuration, validate_remote=True)

View file

@ -1,8 +1,4 @@
import mock def test_password_forgotten(smtpd, testclient, slapd_connection, user):
@mock.patch("smtplib.SMTP")
def test_password_forgotten(SMTP, testclient, slapd_connection, user):
res = testclient.get("/reset", status=200) res = testclient.get("/reset", status=200)
res.form["login"] = "user" res.form["login"] = "user"
@ -10,22 +6,20 @@ def test_password_forgotten(SMTP, testclient, slapd_connection, user):
assert "A password reset link has been sent at your email address." in res.text assert "A password reset link has been sent at your email address." in res.text
assert "Send again" in res.text assert "Send again" in res.text
SMTP.assert_called_once_with(host="localhost", port=25) assert len(smtpd.messages) == 1
@mock.patch("smtplib.SMTP") def test_password_forgotten_invalid_form(smtpd, testclient, slapd_connection, user):
def test_password_forgotten_invalid_form(SMTP, testclient, slapd_connection, user):
res = testclient.get("/reset", status=200) res = testclient.get("/reset", status=200)
res.form["login"] = "" res.form["login"] = ""
res = res.form.submit(status=200) res = res.form.submit(status=200)
assert "Could not send the password reset link." in res.text assert "Could not send the password reset link." in res.text
SMTP.assert_not_called() assert len(smtpd.messages) == 0
@mock.patch("smtplib.SMTP") def test_password_forgotten_invalid(smtpd, testclient, slapd_connection, user):
def test_password_forgotten_invalid(SMTP, testclient, slapd_connection, user):
testclient.app.config["HIDE_INVALID_LOGINS"] = False testclient.app.config["HIDE_INVALID_LOGINS"] = False
res = testclient.get("/reset", status=200) res = testclient.get("/reset", status=200)
@ -42,4 +36,4 @@ def test_password_forgotten_invalid(SMTP, testclient, slapd_connection, user):
assert "A password reset link has been sent at your email address." not in res.text assert "A password reset link has been sent at your email address." not in res.text
assert "The login 'i-dont-really-exist' does not exist" in res.text assert "The login 'i-dont-really-exist' does not exist" in res.text
SMTP.assert_not_called() assert len(smtpd.messages) == 0

View file

@ -1,4 +1,3 @@
import mock
from canaille.models import User from canaille.models import User
@ -182,8 +181,7 @@ def test_user_creation_edition_and_deletion(
assert "george" not in res.text assert "george" not in res.text
@mock.patch("smtplib.SMTP") def test_first_login_mail_button(smtpd, testclient, slapd_connection, logged_admin):
def test_first_login_mail_button(SMTP, testclient, slapd_connection, logged_admin):
User.ocs_by_name(slapd_connection) User.ocs_by_name(slapd_connection)
u = User( u = User(
objectClass=["inetOrgPerson"], objectClass=["inetOrgPerson"],
@ -206,7 +204,7 @@ def test_first_login_mail_button(SMTP, testclient, slapd_connection, logged_admi
in res in res
) )
assert "Send again" in res assert "Send again" in res
SMTP.assert_called_once_with(host="localhost", port=25) assert len(smtpd.messages) == 1
u.reload(slapd_connection) u.reload(slapd_connection)
u.userPassword = ["{SSHA}fw9DYeF/gHTHuVMepsQzVYAkffGcU8Fz"] u.userPassword = ["{SSHA}fw9DYeF/gHTHuVMepsQzVYAkffGcU8Fz"]
@ -216,8 +214,7 @@ def test_first_login_mail_button(SMTP, testclient, slapd_connection, logged_admi
assert "This user does not have a password yet" not in res assert "This user does not have a password yet" not in res
@mock.patch("smtplib.SMTP") def test_email_reset_button(smtpd, testclient, slapd_connection, logged_admin):
def test_email_reset_button(SMTP, testclient, slapd_connection, logged_admin):
User.ocs_by_name(slapd_connection) User.ocs_by_name(slapd_connection)
u = User( u = User(
objectClass=["inetOrgPerson"], objectClass=["inetOrgPerson"],
@ -230,7 +227,7 @@ def test_email_reset_button(SMTP, testclient, slapd_connection, logged_admin):
u.save(slapd_connection) u.save(slapd_connection)
res = testclient.get("/profile/temp", status=200) res = testclient.get("/profile/temp", status=200)
assert "If the user has forgotten his password" in res assert "If the user has forgotten his password" in res, res.text
assert "Send" in res assert "Send" in res
res = res.form.submit(name="action", value="password-reset-mail", status=200) res = res.form.submit(name="action", value="password-reset-mail", status=200)
@ -239,4 +236,4 @@ def test_email_reset_button(SMTP, testclient, slapd_connection, logged_admin):
in res in res
) )
assert "Send again" in res assert "Send again" in res
SMTP.assert_called_once_with(host="localhost", port=25) assert len(smtpd.messages) == 1