-
-
Notifications
You must be signed in to change notification settings - Fork 447
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: remove admin monkey patching
- rename admin site classes to use the module namespace. BREAKING CHANGE: Sites will need to explicitly use TwoFactorAdminSite or extend the TwoFactorAdminSiteMixin
- Loading branch information
Showing
10 changed files
with
131 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,100 @@ | ||
from django.conf import settings | ||
from django.shortcuts import resolve_url | ||
|
||
from unittest import mock | ||
|
||
from django.shortcuts import reverse | ||
from django.test import TestCase | ||
from django.test.utils import override_settings | ||
|
||
from two_factor.admin import patch_admin, unpatch_admin | ||
|
||
from .utils import UserMixin | ||
|
||
|
||
@override_settings(ROOT_URLCONF='tests.urls_admin') | ||
class AdminPatchTest(TestCase): | ||
|
||
def setUp(self): | ||
patch_admin() | ||
class TwoFactorAdminSiteTest(UserMixin, TestCase): | ||
""" | ||
otp_admin is admin console that needs OTP for access. | ||
Only admin users (is_staff and is_active) | ||
with OTP can access it. | ||
""" | ||
|
||
def test_anonymous_get_admin_index_redirects_to_admin_login(self): | ||
index_url = reverse('admin:index') | ||
login_url = reverse('admin:login') | ||
response = self.client.get(index_url, follow=True) | ||
redirect_to = '%s?next=%s' % (login_url, index_url) | ||
self.assertRedirects(response, redirect_to) | ||
|
||
def tearDown(self): | ||
unpatch_admin() | ||
def test_anonymous_get_admin_logout_redirects_to_admin_index(self): | ||
# see: django.tests.admin_views.test_client_logout_url_can_be_used_to_login | ||
index_url = reverse('admin:index') | ||
logout_url = reverse('admin:logout') | ||
response = self.client.get(logout_url) | ||
self.assertEqual( | ||
response.status_code, 302 | ||
) | ||
self.assertEqual(response.get('Location'), index_url) | ||
|
||
def test_anonymous_get_admin_login(self): | ||
login_url = reverse('admin:login') | ||
response = self.client.get(login_url, follow=True) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test(self): | ||
response = self.client.get('/admin/', follow=True) | ||
redirect_to = '%s?next=/admin/' % resolve_url(settings.LOGIN_URL) | ||
def test_is_staff_not_verified_not_setup_get_admin_index_redirects_to_setup(self): | ||
""" | ||
admins without MFA setup should be redirected to the setup page. | ||
""" | ||
index_url = reverse('admin:index') | ||
setup_url = reverse('two_factor:setup') | ||
self.user = self.create_superuser() | ||
self.login_user() | ||
response = self.client.get(index_url, follow=True) | ||
redirect_to = '%s?next=%s' % (setup_url, index_url) | ||
self.assertRedirects(response, redirect_to) | ||
|
||
@override_settings(LOGIN_URL='two_factor:login') | ||
def test_named_url(self): | ||
response = self.client.get('/admin/', follow=True) | ||
redirect_to = '%s?next=/admin/' % resolve_url(settings.LOGIN_URL) | ||
def test_is_staff_not_verified_not_setup_get_admin_login_redirects_to_setup(self): | ||
index_url = reverse('admin:index') | ||
login_url = reverse('admin:login') | ||
setup_url = reverse('two_factor:setup') | ||
self.user = self.create_superuser() | ||
self.login_user() | ||
response = self.client.get(login_url, follow=True) | ||
redirect_to = '%s?next=%s' % (setup_url, index_url) | ||
self.assertRedirects(response, redirect_to) | ||
|
||
|
||
@override_settings(ROOT_URLCONF='tests.urls_admin') | ||
class AdminSiteTest(UserMixin, TestCase): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
def test_is_staff_is_verified_get_admin_index(self): | ||
index_url = reverse('admin:index') | ||
self.user = self.create_superuser() | ||
self.enable_otp(self.user) | ||
self.login_user() | ||
|
||
def test_default_admin(self): | ||
response = self.client.get('/admin/') | ||
response = self.client.get(index_url) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
|
||
@override_settings(ROOT_URLCONF='tests.urls_otp_admin') | ||
class OTPAdminSiteTest(UserMixin, TestCase): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
def test_is_staff_is_verified_get_admin_password_change(self): | ||
password_change_url = reverse('admin:password_change') | ||
self.user = self.create_superuser() | ||
self.enable_otp(self.user) | ||
self.login_user() | ||
response = self.client.get(password_change_url) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_otp_admin_without_otp(self): | ||
response = self.client.get('/otp_admin/', follow=True) | ||
redirect_to = '%s?next=/otp_admin/' % resolve_url(settings.LOGIN_URL) | ||
self.assertRedirects(response, redirect_to) | ||
|
||
@override_settings(LOGIN_URL='two_factor:login') | ||
def test_otp_admin_without_otp_named_url(self): | ||
response = self.client.get('/otp_admin/', follow=True) | ||
redirect_to = '%s?next=/otp_admin/' % resolve_url(settings.LOGIN_URL) | ||
self.assertRedirects(response, redirect_to) | ||
|
||
def test_otp_admin_with_otp(self): | ||
self.enable_otp() | ||
def test_is_staff_is_verified_get_admin_login_redirects_to_admin_index(self): | ||
login_url = reverse('admin:login') | ||
index_url = reverse('admin:index') | ||
self.user = self.create_superuser() | ||
self.enable_otp(self.user) | ||
self.login_user() | ||
response = self.client.get('/otp_admin/') | ||
response = self.client.get(login_url) | ||
self.assertEqual(response.get('Location'), index_url) | ||
|
||
@mock.patch('two_factor.views.core.signals.user_verified.send') | ||
def test_valid_login(self, mock_signal): | ||
login_url = reverse('admin:login') | ||
self.user = self.create_user() | ||
self.enable_otp(self.user) | ||
data = {'auth-username': '[email protected]', | ||
'auth-password': 'secret', | ||
'login_view-current_step': 'auth'} | ||
response = self.client.post(login_url, data=data) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
# No signal should be fired for non-verified user logins. | ||
self.assertFalse(mock_signal.called) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
from django.contrib import admin | ||
from django.urls import path | ||
|
||
from two_factor.admin import TwoFactorAdminSite | ||
|
||
from .urls import urlpatterns | ||
|
||
urlpatterns += [ | ||
path('admin/', admin.site.urls), | ||
path('admin/', TwoFactorAdminSite().urls), | ||
] |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,6 @@ | ||
from django.apps import AppConfig | ||
from django.conf import settings | ||
|
||
|
||
class TwoFactorConfig(AppConfig): | ||
name = 'two_factor' | ||
verbose_name = "Django Two Factor Authentication" | ||
|
||
def ready(self): | ||
if getattr(settings, 'TWO_FACTOR_PATCH_ADMIN', True): | ||
from .admin import patch_admin | ||
patch_admin() |