canaille-globuzma/tests/core/test_intruder_lockout.py

147 lines
4.7 KiB
Python
Raw Normal View History

import datetime
import logging
import time_machine
from canaille.backends.ldap.backend import LDAPBackend
from canaille.core.models import PASSWORD_MIN_DELAY
def test_intruder_lockout_fail_second_attempt_then_succeed_in_third(
testclient, user, caplog
):
testclient.app.config["CANAILLE"]["ENABLE_INTRUDER_LOCKOUT"] = True
with testclient.session_transaction() as session:
assert not session.get("user_id")
# add 500 milliseconds to account for LDAP time
with time_machine.travel(
datetime.datetime.now(datetime.timezone.utc)
+ datetime.timedelta(milliseconds=500),
tick=False,
) as traveller:
res = testclient.get("/login", status=200)
res.form["login"] = "user"
res = res.form.submit(status=302).follow()
res.form["password"] = "incorrect horse"
res = res.form.submit(status=200)
assert ("error", "Login failed, please check your information") in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=200)
assert (
"error",
f"Too much attempts. Please wait for {PASSWORD_MIN_DELAY} seconds before trying to login again.",
) in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
traveller.shift(datetime.timedelta(seconds=PASSWORD_MIN_DELAY))
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=302)
assert (
"success",
"Connection successful. Welcome John (johnny) Doe",
) in res.flashes
assert (
"canaille",
logging.SECURITY,
"Succeed login attempt for user from unknown IP",
) in caplog.record_tuples
def test_intruder_lockout_two_consecutive_fails(testclient, backend, user, caplog):
testclient.app.config["CANAILLE"]["ENABLE_INTRUDER_LOCKOUT"] = True
# add 100 milliseconds to account for LDAP time
with time_machine.travel(
datetime.datetime.now(datetime.timezone.utc)
+ datetime.timedelta(milliseconds=100),
tick=False,
) as traveller:
res = testclient.get("/login", status=200)
res.form["login"] = "user"
res = res.form.submit().follow()
res.form["password"] = "incorrect horse"
res = res.form.submit(status=200)
assert ("error", "Login failed, please check your information") in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=200)
assert (
"error",
f"Too much attempts. Please wait for {PASSWORD_MIN_DELAY} seconds before trying to login again.",
) in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
traveller.shift(datetime.timedelta(seconds=PASSWORD_MIN_DELAY))
ldap_shift = (
PASSWORD_MIN_DELAY if isinstance(backend, LDAPBackend) else 0
) # LDAP doesn't travel in time!
res.form["password"] = "incorrect horse"
res = res.form.submit(status=200)
assert ("error", "Login failed, please check your information") in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=200)
assert (
"error",
f"Too much attempts. Please wait for {PASSWORD_MIN_DELAY*2 - ldap_shift} seconds before trying to login again.",
) in res.flashes
assert (
"canaille",
logging.SECURITY,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
traveller.shift(datetime.timedelta(seconds=PASSWORD_MIN_DELAY * 2))
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=302)
assert (
"success",
"Connection successful. Welcome John (johnny) Doe",
) in res.flashes
assert (
"canaille",
logging.SECURITY,
"Succeed login attempt for user from unknown IP",
) in caplog.record_tuples