feat: sign in/out events are logged in #177

This commit is contained in:
Éloi Rivard 2024-04-09 10:04:26 +02:00
parent 053156ec18
commit 920395c27f
No known key found for this signature in database
GPG key ID: 7EDA204EA57DD184
5 changed files with 56 additions and 4 deletions

View file

@ -1,3 +1,8 @@
Added
^^^^^
- Sign in/out events are logged in :issuer:`177`
[0.0.49] - 2024-04-08
---------------------

View file

@ -259,8 +259,9 @@ class CoreSettings(BaseModel):
LOGGING: Optional[Union[str, Dict]] = None
"""Configures the logging output using the python logging configuration format:
- if :py:data:`None`, everything is logged in the standard output
the log level is :py:data:`~logging.DEBUG` if the :attr:`~canaille.app.configuration.RootSettings.DEBUG` setting is :py:data:`True`, else this is :py:data:`~logging.INFO`
- if :py:data:`None`, everything is logged in the standard error output
the log level is :py:data:`~logging.DEBUG` if the :attr:`~canaille.app.configuration.RootSettings.DEBUG`
setting is :py:data:`True`, else this is :py:data:`~logging.INFO`
- if this is a :class:`dict`, it is passed to :func:`logging.config.dictConfig`:
- if this is a :class:`str`, it is expected to be a file path that will be passed
to :func:`logging.config.fileConfig`

View file

@ -85,13 +85,20 @@ def password():
)
success, message = BaseBackend.get().check_user_password(user, form.password.data)
request_ip = request.remote_addr or "unknown IP"
if not success:
logout_user()
current_app.logger.info(
f'Failed login attempt for {session["attempt_login"]} from {request_ip}'
)
flash(message or _("Login failed, please check your information"), "error")
return render_template(
"password.html", form=form, username=session["attempt_login"]
)
current_app.logger.info(
f'Succeed login attempt for {session["attempt_login"]} from {request_ip}'
)
del session["attempt_login"]
login_user(user)
flash(
@ -106,6 +113,9 @@ def logout():
user = current_user()
if user:
request_ip = request.remote_addr or "unknown IP"
current_app.logger.info(f"Logout {user.identifier} from {request_ip}")
flash(
_(
"You have been disconnected. See you next time %(user)s",

View file

@ -126,6 +126,26 @@ def configuration(smtpd):
"PASSWORD": smtpd.config.login_password,
"FROM_ADDR": "admin@mydomain.tld",
},
"LOGGING": {
"version": 1,
"formatters": {
"default": {
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s",
}
},
"handlers": {
"wsgi": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
"formatter": "default",
}
},
"root": {"level": "DEBUG", "handlers": ["wsgi"]},
"loggers": {
"faker": {"level": "WARNING"},
},
"disable_existing_loggers": False,
},
},
}
return conf

View file

@ -1,4 +1,5 @@
import datetime
import logging
from unittest import mock
from flask import g
@ -20,7 +21,7 @@ def test_index(testclient, user):
assert res.location == "/about"
def test_signin_and_out(testclient, user):
def test_signin_and_out(testclient, user, caplog):
with testclient.session_transaction() as session:
assert not session.get("user_id")
@ -40,6 +41,11 @@ def test_signin_and_out(testclient, user):
"success",
"Connection successful. Welcome John (johnny) Doe",
) in res.flashes
assert (
"canaille",
logging.INFO,
"Succeed login attempt for user from unknown IP",
) in caplog.record_tuples
res = res.follow(status=302)
res = res.follow(status=200)
@ -54,6 +60,11 @@ def test_signin_and_out(testclient, user):
"success",
"You have been disconnected. See you next time John (johnny) Doe",
) in res.flashes
assert (
"canaille",
logging.INFO,
"Logout user from unknown IP",
) in caplog.record_tuples
res = res.follow(status=302)
res = res.follow(status=200)
@ -74,7 +85,7 @@ def test_visitor_logout(testclient, user):
assert not session.get("user_id")
def test_signin_wrong_password(testclient, user):
def test_signin_wrong_password(testclient, user, caplog):
with testclient.session_transaction() as session:
assert not session.get("user_id")
@ -86,6 +97,11 @@ def test_signin_wrong_password(testclient, user):
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.INFO,
"Failed login attempt for user from unknown IP",
) in caplog.record_tuples
def test_signin_password_substring(testclient, user):