forked from Github-Mirrors/canaille
implemented a function that checks some parts of the configuration
This commit is contained in:
parent
30e071dcaf
commit
d0b4121945
6 changed files with 152 additions and 84 deletions
|
@ -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(
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
37
tests/test_configuration.py
Normal file
37
tests/test_configuration.py
Normal 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)
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue