mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
better throttling, doc updated
This commit is contained in:
@@ -123,9 +123,41 @@ Specific instructions
|
||||
|
||||
|
||||
* You now have the possibility to customize the url of the new-admin interface.
|
||||
|
||||
To do so please head up to :ref:`the custom configuration chapter <customization>` (advanced user).
|
||||
|
||||
|
||||
* Add ``DEFAULT_THROTTLE_RATES`` to ``REST_FRAMEWORK``:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'user': '300/minute',
|
||||
'ddos': '5/second',
|
||||
'ddos_lesser': '200/minute',
|
||||
'login': '10/minute',
|
||||
'password_recovery_request': '12/hour',
|
||||
'password_recovery_totp_check': '25/hour',
|
||||
'password_recovery_apply': '25/hour'
|
||||
},
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'modoboa.core.drf_authentication.JWTAuthenticationWith2FA',
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
),
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
|
||||
}
|
||||
|
||||
* You can edit the ``DEFAULT_THROTTLE_RATES`` to whatever value suits you.
|
||||
- `user` is for every endpoint, it is per user or per ip if not logged.
|
||||
- `ddos` is per api endpoint and per user or per ip if not logged.
|
||||
- `ddos_lesser` is for per api endpoint and per user or per ip if not logged. This is for api endpoint that are lighter.
|
||||
- `login` the number of time an ip can attempt to log. The counter will reset on login success.
|
||||
- `password_` is for the recovery, it is divided per step in the recovery process.
|
||||
|
||||
|
||||
2.0.3
|
||||
=====
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from rest_framework.views import APIView
|
||||
|
||||
from modoboa.core.password_hashers import get_password_hasher
|
||||
from modoboa.core.utils import check_for_updates
|
||||
from modoboa.lib.throttle import UserLesserDdosUser
|
||||
from modoboa.lib.throttle import UserLesserDdosUser, LoginThrottle, PasswordResetApplyThrottle, PasswordResetRequestThrottle, PasswordResetTotpThrottle
|
||||
from modoboa.parameters import tools as param_tools
|
||||
|
||||
from smtplib import SMTPException
|
||||
@@ -30,8 +30,7 @@ logger = logging.getLogger("modoboa.auth")
|
||||
class TokenObtainPairView(jwt_views.TokenObtainPairView):
|
||||
"""We overwrite this view to deal with password scheme update."""
|
||||
|
||||
throttle_classes = [ScopedRateThrottle]
|
||||
throttle_scope = "login"
|
||||
throttle_classes = [LoginThrottle]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
@@ -47,6 +46,10 @@ class TokenObtainPairView(jwt_views.TokenObtainPairView):
|
||||
|
||||
user = serializer.user
|
||||
login(request, user)
|
||||
|
||||
# Reset login throttle
|
||||
self.get_throttles()[0].reset_cache(request)
|
||||
|
||||
logger.info(
|
||||
_("User '%s' successfully logged in"), user.username
|
||||
)
|
||||
@@ -90,8 +93,7 @@ class EmailPasswordResetView(APIView):
|
||||
An Api View which provides a method to request a password reset token based on an e-mail address.
|
||||
"""
|
||||
|
||||
throttle_classes = [ScopedRateThrottle]
|
||||
throttle_scope = 'password_recovery_request'
|
||||
throttle_classes = [PasswordResetRequestThrottle]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = serializers.PasswordRecoveryEmailSerializer(
|
||||
@@ -104,6 +106,8 @@ class EmailPasswordResetView(APIView):
|
||||
"type": "email",
|
||||
"reason": "Error while sending the email. Please contact an administrator."
|
||||
}, 503)
|
||||
|
||||
self.get_throttles()[0].reset_cache(request)
|
||||
# Email response
|
||||
return response.Response({"type": "email"}, 200)
|
||||
|
||||
@@ -123,14 +127,14 @@ class DefaultPasswordResetView(EmailPasswordResetView):
|
||||
except serializers.NoSMSAvailable:
|
||||
return super().post(request, *args, **kwargs)
|
||||
# SMS response
|
||||
self.get_throttles()[0].reset_cache(request)
|
||||
return response.Response({"type": "sms"}, 200)
|
||||
|
||||
|
||||
class PasswordResetSmsTOTP(APIView):
|
||||
""" Check SMS Totp code. """
|
||||
|
||||
throttle_classes = [ScopedRateThrottle]
|
||||
throttle_scope = 'password_recovery_totp_check'
|
||||
throttle_classes = [PasswordResetTotpThrottle]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
try:
|
||||
@@ -151,14 +155,14 @@ class PasswordResetSmsTOTP(APIView):
|
||||
"id": serializer_response[1],
|
||||
"type": "confirm"
|
||||
})
|
||||
self.get_throttles()[0].reset_cache(request)
|
||||
return response.Response(payload, 200)
|
||||
|
||||
|
||||
class PasswordResetConfirmView(APIView):
|
||||
""" Get and set new user password. """
|
||||
|
||||
throttle_classes = [ScopedRateThrottle]
|
||||
throttle_scope = 'password_recovery_apply'
|
||||
throttle_classes = [PasswordResetApplyThrottle]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = serializers.PasswordRecoveryConfirmSerializer(
|
||||
@@ -173,6 +177,7 @@ class PasswordResetConfirmView(APIView):
|
||||
data.update({"errors": errors})
|
||||
return response.Response(data, 400)
|
||||
serializer.save()
|
||||
self.get_throttles()[0].reset_cache(request)
|
||||
return response.Response(status=200)
|
||||
|
||||
|
||||
|
||||
@@ -28,9 +28,13 @@ from . import serializers
|
||||
class AccountViewSet(core_v1_viewsets.AccountViewSet):
|
||||
"""Account viewset."""
|
||||
|
||||
throttle_classes = [UserRateThrottle]
|
||||
|
||||
def get_throttles(self):
|
||||
if self.action in ['me']:
|
||||
self.throttle_classes.append(UserLesserDdosUser)
|
||||
else:
|
||||
self.throttle_classes.append(UserDdosPerView)
|
||||
return super().get_throttles()
|
||||
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ REST_FRAMEWORK = {
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'user': '300/minute',
|
||||
'ddos': '5/second',
|
||||
'ddos_lesser': '10/second',
|
||||
'login': '5/minute',
|
||||
'password_recovery_request': '6/hour',
|
||||
'password_recovery_totp_check': '20/hour',
|
||||
'password_recovery_apply': '40/hour'
|
||||
'ddos_lesser': '200/minute',
|
||||
'login': '10/minute',
|
||||
'password_recovery_request': '12/hour',
|
||||
'password_recovery_totp_check': '25/hour',
|
||||
'password_recovery_apply': '25/hour'
|
||||
},
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'modoboa.core.drf_authentication.JWTAuthenticationWith2FA',
|
||||
|
||||
+34
-3
@@ -1,4 +1,5 @@
|
||||
from rest_framework.throttling import SimpleRateThrottle
|
||||
from rest_framework.throttling import SimpleRateThrottle, AnonRateThrottle
|
||||
from django.urls import resolve
|
||||
|
||||
class UserDdosPerView(SimpleRateThrottle):
|
||||
"""Custom Throttle class for rest_framework. The throttling is applied on a per view basis for authentificated users."""
|
||||
@@ -11,7 +12,7 @@ class UserDdosPerView(SimpleRateThrottle):
|
||||
else:
|
||||
ident = self.get_ident(request)
|
||||
return self.cache_format % {
|
||||
'scope': hash(request.path),
|
||||
'scope': hash(resolve(request.path).url_name),
|
||||
'ident': ident
|
||||
}
|
||||
|
||||
@@ -26,6 +27,36 @@ class UserLesserDdosUser(SimpleRateThrottle):
|
||||
else:
|
||||
ident = self.get_ident(request)
|
||||
return self.cache_format % {
|
||||
'scope': hash(request.path),
|
||||
'scope': hash(resolve(request.path).url_name),
|
||||
'ident': ident
|
||||
}
|
||||
|
||||
class LoginThrottle(SimpleRateThrottle):
|
||||
|
||||
scope = 'login'
|
||||
|
||||
def get_cache_key(self, request, view = None):
|
||||
return self.cache_format % {
|
||||
'scope': self.scope,
|
||||
'ident': self.get_ident(request)
|
||||
}
|
||||
|
||||
def reset_cache(self, request):
|
||||
self.key = self.get_cache_key(request)
|
||||
self.cache.delete(self.key)
|
||||
|
||||
|
||||
class PasswordResetRequestThrottle(LoginThrottle):
|
||||
|
||||
scope = 'password_recovery_request'
|
||||
|
||||
|
||||
class PasswordResetTotpThrottle(LoginThrottle):
|
||||
|
||||
scope = 'password_recovery_totp_check'
|
||||
|
||||
|
||||
class PasswordResetApplyThrottle(LoginThrottle):
|
||||
|
||||
scope = 'password_recovery_apply'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user