mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-20 02:48:51 +00:00
[auth] add captcha to prevent brute force attack
This commit is contained in:
@@ -9,6 +9,8 @@ from seahub.auth import authenticate
|
|||||||
from seahub.auth.tokens import default_token_generator
|
from seahub.auth.tokens import default_token_generator
|
||||||
from seahub.utils import IS_EMAIL_CONFIGURED
|
from seahub.utils import IS_EMAIL_CONFIGURED
|
||||||
|
|
||||||
|
from captcha.fields import CaptchaField
|
||||||
|
|
||||||
class AuthenticationForm(forms.Form):
|
class AuthenticationForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
Base class for authenticating users. Extend this to get a form that accepts
|
Base class for authenticating users. Extend this to get a form that accepts
|
||||||
@@ -26,7 +28,10 @@ class AuthenticationForm(forms.Form):
|
|||||||
"""
|
"""
|
||||||
self.request = request
|
self.request = request
|
||||||
self.user_cache = None
|
self.user_cache = None
|
||||||
|
use_captcha = kwargs.pop('use_captcha', False)
|
||||||
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
||||||
|
if use_captcha:
|
||||||
|
self.fields['captcha'] = CaptchaField()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
username = self.cleaned_data.get('username')
|
username = self.cleaned_data.get('username')
|
||||||
|
@@ -21,6 +21,9 @@ from seahub.auth.forms import PasswordResetForm, SetPasswordForm, PasswordChange
|
|||||||
from seahub.auth.tokens import default_token_generator
|
from seahub.auth.tokens import default_token_generator
|
||||||
|
|
||||||
from seahub.base.accounts import User
|
from seahub.base.accounts import User
|
||||||
|
from seahub.base.models import UserLoginAttempt
|
||||||
|
from settings import LOGIN_ATTEMPT_LIMIT, LOGIN_ATTEMPT_TIMEOUT
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
# Get an instance of a logger
|
# Get an instance of a logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -37,9 +40,19 @@ def login(request, template_name='registration/login.html',
|
|||||||
return HttpResponseRedirect(reverse(redirect_if_logged_in))
|
return HttpResponseRedirect(reverse(redirect_if_logged_in))
|
||||||
|
|
||||||
redirect_to = request.REQUEST.get(redirect_field_name, '')
|
redirect_to = request.REQUEST.get(redirect_field_name, '')
|
||||||
|
username = request.REQUEST.get('username', '')
|
||||||
|
if username:
|
||||||
|
login_attempt, created = UserLoginAttempt.objects.get_or_create(username=username)
|
||||||
|
if login_attempt.last_attempt_time + LOGIN_ATTEMPT_TIMEOUT < datetime.now():
|
||||||
|
login_attempt.delete()
|
||||||
|
login_attempt = UserLoginAttempt.objects.create(username=username)
|
||||||
|
if login_attempt.failed_attempts >= LOGIN_ATTEMPT_LIMIT:
|
||||||
|
use_captcha = True
|
||||||
|
else:
|
||||||
|
use_captcha = False
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = authentication_form(data=request.POST)
|
form = authentication_form(data=request.POST, use_captcha=use_captcha)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
# Light security check -- make sure redirect_to isn't garbage.
|
# Light security check -- make sure redirect_to isn't garbage.
|
||||||
if not redirect_to or ' ' in redirect_to:
|
if not redirect_to or ' ' in redirect_to:
|
||||||
@@ -58,7 +71,13 @@ def login(request, template_name='registration/login.html',
|
|||||||
if request.session.test_cookie_worked():
|
if request.session.test_cookie_worked():
|
||||||
request.session.delete_test_cookie()
|
request.session.delete_test_cookie()
|
||||||
|
|
||||||
|
login_attempt.delete()
|
||||||
return HttpResponseRedirect(redirect_to)
|
return HttpResponseRedirect(redirect_to)
|
||||||
|
else:
|
||||||
|
login_attempt.failed_attempts += 1
|
||||||
|
login_attempt.save()
|
||||||
|
if login_attempt.failed_attempts == LOGIN_ATTEMPT_LIMIT:
|
||||||
|
form = authentication_form(data=request.POST, use_captcha=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
form = authentication_form(request)
|
form = authentication_form(request)
|
||||||
|
@@ -322,3 +322,11 @@ class InnerPubMsgReply(models.Model):
|
|||||||
# msg_type='innerpubmsg_reply',
|
# msg_type='innerpubmsg_reply',
|
||||||
# detail=msg_id)
|
# detail=msg_id)
|
||||||
# n.save()
|
# n.save()
|
||||||
|
|
||||||
|
class UserLoginAttempt(models.Model):
|
||||||
|
username = models.CharField(max_length=255)
|
||||||
|
last_attempt_time = models.DateTimeField(auto_now_add=True)
|
||||||
|
failed_attempts = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['-last_attempt_time']
|
||||||
|
@@ -160,6 +160,7 @@ INSTALLED_APPS = (
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
|
|
||||||
'registration',
|
'registration',
|
||||||
|
'captcha',
|
||||||
|
|
||||||
'seahub.api2',
|
'seahub.api2',
|
||||||
'seahub.avatar',
|
'seahub.avatar',
|
||||||
@@ -339,6 +340,11 @@ LOGGING = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#Login Attempt
|
||||||
|
import datetime
|
||||||
|
LOGIN_ATTEMPT_LIMIT = 3
|
||||||
|
LOGIN_ATTEMPT_TIMEOUT = datetime.timedelta(minutes=15)
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Email sending #
|
# Email sending #
|
||||||
#################
|
#################
|
||||||
|
@@ -9,9 +9,14 @@
|
|||||||
<input type="text" id="id_email" name="username" value="" />
|
<input type="text" id="id_email" name="username" value="" />
|
||||||
<label for="password">{% trans "Password" %}</label>
|
<label for="password">{% trans "Password" %}</label>
|
||||||
<input type="password" id="id_password" name="password" value="" />
|
<input type="password" id="id_password" name="password" value="" />
|
||||||
|
{{ form.captcha }}
|
||||||
<input type="hidden" name="next" value="{% if next %}{{ next|escape }}{% else %}{{ SITE_ROOT }}{% endif %}" />
|
<input type="hidden" name="next" value="{% if next %}{{ next|escape }}{% else %}{{ SITE_ROOT }}{% endif %}" />
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
|
{% if form.captcha.errors %}
|
||||||
|
<p class="error">{% trans "Incorrect CAPTCHA" %}</p>
|
||||||
|
{% else %}
|
||||||
<p class="error">{% trans "Incorrect email or password" %}</p>
|
<p class="error">{% trans "Incorrect email or password" %}</p>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="error hide"></p>
|
<p class="error hide"></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -145,6 +145,7 @@ urlpatterns = patterns('',
|
|||||||
(r'^message/', include('seahub.message.urls')),
|
(r'^message/', include('seahub.message.urls')),
|
||||||
(r'^profile/', include('seahub.profile.urls')),
|
(r'^profile/', include('seahub.profile.urls')),
|
||||||
(r'^share/', include('seahub.share.urls')),
|
(r'^share/', include('seahub.share.urls')),
|
||||||
|
url(r'^captcha/', include('captcha.urls')),
|
||||||
|
|
||||||
### system admin ###
|
### system admin ###
|
||||||
url(r'^sys/seafadmin/$', sys_repo_admin, name='sys_repo_admin'),
|
url(r'^sys/seafadmin/$', sys_repo_admin, name='sys_repo_admin'),
|
||||||
|
Reference in New Issue
Block a user