Mercurial > kallithea
changeset 7701:9c2fc1390291
tests: prepare for adding CSRF protection on login forms
CSRF is about avoiding abuse of credentials by doing things in existing
sessions. The login form does not have any previous credentials, so there is
nothing to abuse and no real need for CSRF protection. But there is still an
unauth session, so we *can* have CSRF protection.
CSRF protection is currently in LoginRequired (which obviously isn't
applied to the login form), but let's prepare for changing that.
author | Mads Kiilerich <mads@kiilerich.com> |
---|---|
date | Fri, 04 Jan 2019 03:42:17 +0100 |
parents | ffdcf0dfe0e4 |
children | 797883404f17 |
files | kallithea/tests/base.py kallithea/tests/functional/test_login.py |
diffstat | 2 files changed, 52 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/kallithea/tests/base.py Wed Jan 23 00:56:18 2019 +0100 +++ b/kallithea/tests/base.py Fri Jan 04 03:42:17 2019 +0100 @@ -154,7 +154,8 @@ self._logged_username = username response = self.app.post(url(controller='login', action='index'), {'username': username, - 'password': password}) + 'password': password, + '_authentication_token': self.authentication_token()}) if 'Invalid username or password' in response.body: pytest.fail('could not login using %s %s' % (username, password))
--- a/kallithea/tests/functional/test_login.py Wed Jan 23 00:56:18 2019 +0100 +++ b/kallithea/tests/functional/test_login.py Fri Jan 04 03:42:17 2019 +0100 @@ -31,7 +31,8 @@ def test_login_admin_ok(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_ADMIN_LOGIN, - 'password': TEST_USER_ADMIN_PASS}) + 'password': TEST_USER_ADMIN_PASS, + '_authentication_token': self.authentication_token()}) assert response.status == '302 Found' self.assert_authenticated_user(response, TEST_USER_ADMIN_LOGIN) @@ -41,7 +42,8 @@ def test_login_regular_ok(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_LOGIN, - 'password': TEST_USER_REGULAR_PASS}) + 'password': TEST_USER_REGULAR_PASS, + '_authentication_token': self.authentication_token()}) assert response.status == '302 Found' self.assert_authenticated_user(response, TEST_USER_REGULAR_LOGIN) @@ -52,7 +54,8 @@ def test_login_regular_email_ok(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_EMAIL, - 'password': TEST_USER_REGULAR_PASS}) + 'password': TEST_USER_REGULAR_PASS, + '_authentication_token': self.authentication_token()}) assert response.status == '302 Found' self.assert_authenticated_user(response, TEST_USER_REGULAR_LOGIN) @@ -65,7 +68,8 @@ response = self.app.post(url(controller='login', action='index', came_from=test_came_from), {'username': TEST_USER_ADMIN_LOGIN, - 'password': TEST_USER_ADMIN_PASS}) + 'password': TEST_USER_ADMIN_PASS, + '_authentication_token': self.authentication_token()}) assert response.status == '302 Found' response = response.follow() @@ -76,7 +80,8 @@ response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_LOGIN, 'password': TEST_USER_REGULAR_PASS, - 'remember': False}) + 'remember': False, + '_authentication_token': self.authentication_token()}) assert 'Set-Cookie' in response.headers for cookie in response.headers.getall('Set-Cookie'): @@ -86,7 +91,8 @@ response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_LOGIN, 'password': TEST_USER_REGULAR_PASS, - 'remember': True}) + 'remember': True, + '_authentication_token': self.authentication_token()}) assert 'Set-Cookie' in response.headers for cookie in response.headers.getall('Set-Cookie'): @@ -95,7 +101,8 @@ def test_logout(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_LOGIN, - 'password': TEST_USER_REGULAR_PASS}) + 'password': TEST_USER_REGULAR_PASS, + '_authentication_token': self.authentication_token()}) # Verify that a login session has been established. response = self.app.get(url(controller='login', action='index')) @@ -123,13 +130,15 @@ response = self.app.post(url(controller='login', action='index', came_from=url_came_from), {'username': TEST_USER_ADMIN_LOGIN, - 'password': TEST_USER_ADMIN_PASS}, + 'password': TEST_USER_ADMIN_PASS, + '_authentication_token': self.authentication_token()}, status=400) def test_login_short_password(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_ADMIN_LOGIN, - 'password': 'as'}) + 'password': 'as', + '_authentication_token': self.authentication_token()}) assert response.status == '200 OK' response.mustcontain('Enter 3 characters or more') @@ -137,14 +146,16 @@ def test_login_wrong_username_password(self): response = self.app.post(url(controller='login', action='index'), {'username': 'error', - 'password': 'test12'}) + 'password': 'test12', + '_authentication_token': self.authentication_token()}) response.mustcontain('Invalid username or password') def test_login_non_ascii(self): response = self.app.post(url(controller='login', action='index'), {'username': TEST_USER_REGULAR_LOGIN, - 'password': 'blåbærgrød'}) + 'password': 'blåbærgrød', + '_authentication_token': self.authentication_token()}) response.mustcontain('>Invalid username or password<') @@ -187,7 +198,8 @@ response = self.app.post(url(controller='login', action='index', came_from=url('/_admin/users', **args)), {'username': TEST_USER_ADMIN_LOGIN, - 'password': TEST_USER_ADMIN_PASS}) + 'password': TEST_USER_ADMIN_PASS, + '_authentication_token': self.authentication_token()}) assert response.status == '302 Found' for encoded in args_encoded: assert encoded in response.location @@ -201,7 +213,8 @@ response = self.app.post(url(controller='login', action='index', came_from=url('/_admin/users', **args)), {'username': 'error', - 'password': 'test12'}) + 'password': 'test12', + '_authentication_token': self.authentication_token()}) response.mustcontain('Invalid username or password') came_from = urlparse.parse_qs(urlparse.urlparse(response.form.action).query)['came_from'][0] @@ -223,7 +236,8 @@ 'password_confirmation': 'test12', 'email': 'goodmail@example.com', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) with test_context(self.app): msg = validators.ValidUsername()._messages['username_exists'] @@ -237,7 +251,8 @@ 'password_confirmation': 'test12', 'email': TEST_USER_ADMIN_EMAIL, 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) with test_context(self.app): msg = validators.UniqSystemEmail()()._messages['email_taken'] @@ -250,7 +265,8 @@ 'password_confirmation': 'test12', 'email': TEST_USER_ADMIN_EMAIL.title(), 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) with test_context(self.app): msg = validators.UniqSystemEmail()()._messages['email_taken'] response.mustcontain(msg) @@ -262,7 +278,8 @@ 'password_confirmation': 'test', 'email': 'goodmailm', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) assert response.status == '200 OK' response.mustcontain('An email address must contain a single @') response.mustcontain('Enter a value 6 characters long or more') @@ -274,7 +291,8 @@ 'password_confirmation': 'test12', 'email': 'goodmailm', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) response.mustcontain('An email address must contain a single @') response.mustcontain('Username may only contain ' @@ -290,7 +308,8 @@ 'password_confirmation': 'test12', 'email': 'goodmailm', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) response.mustcontain('An email address must contain a single @') with test_context(self.app): @@ -305,7 +324,8 @@ 'password_confirmation': 'ąćźżąśśśś', 'email': 'goodmailm@test.plx', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) with test_context(self.app): msg = validators.ValidPassword()._messages['invalid_password'] @@ -318,7 +338,8 @@ 'password_confirmation': 'qwe123', 'email': 'goodmailm@test.plxa', 'firstname': 'test', - 'lastname': 'test'}) + 'lastname': 'test', + '_authentication_token': self.authentication_token()}) with test_context(self.app): msg = validators.ValidPasswordsMatch('password', 'password_confirmation')._messages['password_mismatch'] response.mustcontain(msg) @@ -337,7 +358,8 @@ 'email': email, 'firstname': name, 'lastname': lastname, - 'admin': True}) # This should be overridden + 'admin': True, + '_authentication_token': self.authentication_token()}) # This should be overridden assert response.status == '302 Found' self.checkSessionFlash(response, 'You have successfully registered with Kallithea') @@ -358,8 +380,8 @@ bad_email = 'username%wrongmail.org' response = self.app.post( url(controller='login', action='password_reset'), - {'email': bad_email, } - ) + {'email': bad_email, + '_authentication_token': self.authentication_token()}) response.mustcontain('An email address must contain a single @') @@ -387,7 +409,8 @@ response = self.app.post(url(controller='login', action='password_reset'), - {'email': email, }) + {'email': email, + '_authentication_token': self.authentication_token()}) self.checkSessionFlash(response, 'A password reset confirmation code has been sent') @@ -404,6 +427,7 @@ 'password': "p@ssw0rd", 'password_confirm': "p@ssw0rd", 'token': token, + '_authentication_token': self.authentication_token(), }) assert response.status == '200 OK' response.mustcontain('Invalid password reset token') @@ -431,6 +455,7 @@ 'password': "p@ssw0rd", 'password_confirm': "p@ssw0rd", 'token': token, + '_authentication_token': self.authentication_token(), }) assert response.status == '302 Found' self.checkSessionFlash(response, 'Successfully updated password')