From 1de3b1eff08ca7b948b9f3f17d827773972765cb Mon Sep 17 00:00:00 2001 From: Spitap Date: Tue, 21 Feb 2023 17:16:01 +0100 Subject: [PATCH 1/2] log message on failed auth --- modoboa/core/api/v2/views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modoboa/core/api/v2/views.py b/modoboa/core/api/v2/views.py index f62425ada..ecfdc75f1 100644 --- a/modoboa/core/api/v2/views.py +++ b/modoboa/core/api/v2/views.py @@ -10,8 +10,9 @@ from django.contrib.auth import login from drf_spectacular.utils import extend_schema from rest_framework import response, status +from rest_framework.exceptions import AuthenticationFailed from rest_framework_simplejwt import views as jwt_views -from rest_framework_simplejwt.exceptions import InvalidToken, TokenError +from rest_framework_simplejwt.exceptions import InvalidToken from rest_framework.views import APIView from modoboa.core.password_hashers import get_password_hasher @@ -28,7 +29,7 @@ logger = logging.getLogger("modoboa.auth") def delete_cache_key(class_target, throttles, request): """Attempt to delete cache key from throttling on login/password reset success.""" - + for throttle in throttles: if type(throttle) == class_target: throttle.reset_cache(request) @@ -44,7 +45,7 @@ class TokenObtainPairView(jwt_views.TokenObtainPairView): serializer = self.get_serializer(data=request.data) try: serializer.is_valid(raise_exception=True) - except TokenError as e: + except AuthenticationFailed as e: logger.warning( _("Failed connection attempt from '%s' as user '%s'"), request.META["REMOTE_ADDR"], @@ -133,7 +134,7 @@ class DefaultPasswordResetView(EmailPasswordResetView): serializer.is_valid(raise_exception=True) except serializers.NoSMSAvailable: return super().post(request, *args, **kwargs) - + # SMS response return response.Response({"type": "sms"}, 200) From ac78cbb7954b0ac3a968f8c6dd91b675312360ca Mon Sep 17 00:00:00 2001 From: Spitap Date: Tue, 21 Feb 2023 18:24:18 +0100 Subject: [PATCH 2/2] fixed serializer error, added test --- modoboa/core/api/v2/tests.py | 19 +++++++++++++++++++ modoboa/core/api/v2/views.py | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/modoboa/core/api/v2/tests.py b/modoboa/core/api/v2/tests.py index ed6bdd5e4..4caae77f7 100644 --- a/modoboa/core/api/v2/tests.py +++ b/modoboa/core/api/v2/tests.py @@ -204,6 +204,25 @@ class AccountViewSetTestCase(ModoAPITestCase): resp = self.client.post(url) self.assertEqual(resp.status_code, 201) + def test_failed_api_token(self): + """Simulate a failed login attempt and check that it is logged.""" + + url = reverse("v2:token_obtain_pair") + data = { + "username": "clearly_non_existent_user", + "password": "password" + } + + with self.assertLogs(logger='modoboa.auth', level='WARNING') as log: + + resp = self.client.post(url, data, format="json") + self.assertEqual(resp.status_code, 401) + self.assertIn( + "WARNING:modoboa.auth:Failed connection attempt from '127.0.0.1'" + " as user 'clearly_non_existent_user'", + log.output + ) + class PasswordResetTestCase(AccountViewSetTestCase): def __init__(self, *args, **kwargs): diff --git a/modoboa/core/api/v2/views.py b/modoboa/core/api/v2/views.py index ecfdc75f1..c8c7ac8d8 100644 --- a/modoboa/core/api/v2/views.py +++ b/modoboa/core/api/v2/views.py @@ -49,7 +49,7 @@ class TokenObtainPairView(jwt_views.TokenObtainPairView): logger.warning( _("Failed connection attempt from '%s' as user '%s'"), request.META["REMOTE_ADDR"], - escape(serializer.data["username"]) + escape(serializer.initial_data["username"]) ) raise InvalidToken(e.args[0])