From 1a59ed6cc4015eef8792db237f0d87c815049238 Mon Sep 17 00:00:00 2001 From: Ricky Rosario Date: Tue, 25 Feb 2014 16:15:36 -0500 Subject: [PATCH] [bug 971000] Protect login with django-axes. --- .gitmodules | 3 --- docs/hacking_howto.rst | 3 +++ kitsune/settings.py | 10 ++++++++++ kitsune/users/views.py | 2 ++ migrations/236-install-django-axes.sql | 25 +++++++++++++++++++++++++ settings_test.py | 3 +++ 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 migrations/236-install-django-axes.sql diff --git a/.gitmodules b/.gitmodules index dbcdc297e..e7bc0e979 100644 --- a/.gitmodules +++ b/.gitmodules @@ -172,6 +172,3 @@ [submodule "vendor/src/django-axes"] path = vendor/src/django-axes url = https://github.com/django-security/django-axes.git -[submodule "vendor/src/django-taggit"] - path = vendor/src/django-taggit - url = https://github.com/alex/django-taggit.git diff --git a/docs/hacking_howto.rst b/docs/hacking_howto.rst index 5c1cded8b..b4ac12dff 100644 --- a/docs/hacking_howto.rst +++ b/docs/hacking_howto.rst @@ -226,6 +226,9 @@ Start with this:: LESS_PREPROCESS = True LESS_BIN = '/path/to/kitsune/node_modules/less/bin/lessc' + # Tells django-axes we aren't behind a reverse proxy. + AXES_BEHIND_REVERSE_PROXY = False + Don't forget to change ```` and update ``LESS_BIN`` based on your setup. diff --git a/kitsune/settings.py b/kitsune/settings.py index 2c37158f6..c465589e7 100644 --- a/kitsune/settings.py +++ b/kitsune/settings.py @@ -449,6 +449,7 @@ MIDDLEWARE_CLASSES = ( 'commonware.middleware.StrictTransportMiddleware', 'commonware.middleware.XSSProtectionHeader', 'commonware.middleware.RobotsTagHeader', + 'axes.middleware.FailedLoginMiddleware' ) # Auth @@ -540,6 +541,7 @@ INSTALLED_APPS = ( 'kitsune.products', 'rest_framework', 'statici18n', + 'axes', # App for Sentry: 'raven.contrib.django', @@ -877,3 +879,11 @@ BROWSERID_AUDIENCES = [ REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',) } + +# Django-axes settings. +AXES_LOGIN_FAILURE_LIMIT = 10 +AXES_LOCK_OUT_AT_FAILURE = True +AXES_USE_USER_AGENT = False +AXES_COOLOFF_TIME = 1 # hour +AXES_BEHIND_REVERSE_PROXY = True +AXES_REVERSE_PROXY_HEADER = 'HTTP_X_CLUSTER_CLIENT_IP' diff --git a/kitsune/users/views.py b/kitsune/users/views.py index fee0e833e..f5fd4179f 100644 --- a/kitsune/users/views.py +++ b/kitsune/users/views.py @@ -20,6 +20,7 @@ from django_browserid.auth import BrowserIDBackend from django_browserid.base import get_audience from django_browserid.forms import BrowserIDForm +from axes.decorators import watch_login from mobility.decorators import mobile_template from session_csrf import anonymous_csrf from statsd import statsd @@ -77,6 +78,7 @@ def user_auth(request, contributor=False, register_form=None, login_form=None): @ssl_required @anonymous_csrf +@watch_login @mobile_template('users/{mobile/}login.html') def login(request, template): """Try to log the user in.""" diff --git a/migrations/236-install-django-axes.sql b/migrations/236-install-django-axes.sql new file mode 100644 index 000000000..17336d35e --- /dev/null +++ b/migrations/236-install-django-axes.sql @@ -0,0 +1,25 @@ +CREATE TABLE `axes_accessattempt` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `user_agent` varchar(255) NOT NULL, + `ip_address` char(15), + `username` varchar(255), + `trusted` bool NOT NULL, + `http_accept` varchar(1025) NOT NULL, + `path_info` varchar(255) NOT NULL, + `attempt_time` datetime NOT NULL, + `get_data` longtext NOT NULL, + `post_data` longtext NOT NULL, + `failures_since_start` integer UNSIGNED NOT NULL +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; + +CREATE TABLE `axes_accesslog` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `user_agent` varchar(255) NOT NULL, + `ip_address` char(15), + `username` varchar(255), + `trusted` bool NOT NULL, + `http_accept` varchar(1025) NOT NULL, + `path_info` varchar(255) NOT NULL, + `attempt_time` datetime NOT NULL, + `logout_time` datetime +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; diff --git a/settings_test.py b/settings_test.py index c265e7f03..b4327239d 100644 --- a/settings_test.py +++ b/settings_test.py @@ -35,3 +35,6 @@ if 'DJANGO_LIVE_TEST_SERVER_ADDRESS' not in os.environ: import logging import south.logger logging.getLogger('south').setLevel(logging.INFO) + +# Tells django-axes we aren't behind a reverse proxy. +AXES_BEHIND_REVERSE_PROXY = False