11import django .apps
22from django .contrib import admin
3+ from django .contrib .auth import get_user_model
4+ from django .urls import reverse
35
46from .dojo_test_case import DojoTestCase
57
@@ -20,3 +22,43 @@ def test_is_model_defined(self):
2022 else :
2123 with self .subTest (type = "tag" , subclass = subclass ):
2224 self .assertIn (subclass , admin .site ._registry .keys (), f"{ subclass } is not registered in 'tagulous.admin' in models.py" )
25+
26+
27+ class AdminAccessGate (DojoTestCase ):
28+
29+ """
30+ is_staff is a near-superuser bypass under the legacy OS auth model, so
31+ /admin/ must require is_superuser. Django's default UserAdmin change
32+ form would otherwise let any is_staff user with auth.change_user tick
33+ is_superuser on themselves.
34+ """
35+
36+ def test_staff_non_superuser_blocked_from_admin (self ):
37+ User = get_user_model ()
38+ staff = User .objects .create_user (
39+ username = "staff-no-root" , password = "x" , is_staff = True ,
40+ )
41+ self .client .force_login (staff )
42+
43+ for url in (
44+ reverse ("admin:index" ),
45+ reverse ("admin:auth_user_changelist" ),
46+ reverse ("admin:auth_user_change" , args = [staff .id ]),
47+ ):
48+ with self .subTest (url = url ):
49+ resp = self .client .get (url )
50+ self .assertEqual (resp .status_code , 302 , url )
51+ self .assertIn ("/admin/login/" , resp ["Location" ], url )
52+
53+ def test_superuser_can_reach_admin (self ):
54+ User = get_user_model ()
55+ root = User .objects .create_superuser (
56+ username = "root-test" , email = "r@example.com" , password = "x" ,
57+ )
58+ self .client .force_login (root )
59+
60+ self .assertEqual (self .client .get (reverse ("admin:index" )).status_code , 200 )
61+ self .assertEqual (
62+ self .client .get (reverse ("admin:auth_user_changelist" )).status_code ,
63+ 200 ,
64+ )
0 commit comments