1+ from functools import update_wrapper
12
23from django .conf import settings
34from django .contrib .admin import AdminSite
67from django .http import HttpResponseRedirect
78from django .shortcuts import resolve_url
89from django .urls import reverse
10+ from django .views .decorators .cache import never_cache
11+ from django .views .decorators .csrf import csrf_protect
912
10- from .utils import monkeypatch_method
13+
14+ from .utils import default_device , monkeypatch_method
1115
1216try :
1317 from django .utils .http import url_has_allowed_host_and_scheme
@@ -25,33 +29,92 @@ class AdminSiteOTPRequiredMixin:
2529 use :meth:`has_permission` in order to secure those views.
2630 """
2731
32+ def has_admin_permission (self , request ):
33+ return super ().has_permission (request )
34+
2835 def has_permission (self , request ):
2936 """
3037 Returns True if the given HttpRequest has permission to view
3138 *at least one* page in the admin site.
3239 """
33- if not super ().has_permission (request ):
34- return False
35- return request .user .is_verified ()
40+ print ("AdminSiteOTPRequiredMixin.has_permission, self.has_admin_permission(request)" , self .has_admin_permission (request ), request .user .is_verified ())
41+ return self .has_admin_permission (request ) and request .user .is_verified ()
42+
43+ def admin_view (self , view , cacheable = False ):
44+ """
45+ Decorator to create an admin view attached to this ``AdminSite``. This
46+ wraps the view and provides permission checking by calling
47+ ``self.has_permission``.
48+
49+ You'll want to use this from within ``AdminSite.get_urls()``:
3650
51+ class MyAdminSite(AdminSite):
52+
53+ def get_urls(self):
54+ from django.urls import path
55+
56+ urls = super().get_urls()
57+ urls += [
58+ path('my_view/', self.admin_view(some_view))
59+ ]
60+ return urls
61+
62+ By default, admin_views are marked non-cacheable using the
63+ ``never_cache`` decorator. If the view can be safely cached, set
64+ cacheable=True.
65+ """
66+ def inner (request , * args , ** kwargs ):
67+ print ("AdminSiteOTPRequiredMixin.admin_view.inner" , )
68+ if not self .has_permission (request ):
69+ if request .path == reverse ('admin:logout' , current_app = self .name ):
70+ index_path = reverse ('admin:index' , current_app = self .name )
71+ return HttpResponseRedirect (index_path )
72+
73+ if (self .has_admin_permission (request ) and not default_device (request .user )):
74+ index_path = reverse ("two_factor:setup" , current_app = self .name )
75+ return HttpResponseRedirect (index_path )
76+
77+ # Inner import to prevent django.contrib.admin (app) from
78+ # importing django.contrib.auth.models.User (unrelated model).
79+ from django .contrib .auth .views import redirect_to_login
80+ return redirect_to_login (
81+ request .get_full_path (),
82+ reverse ('admin:login' , current_app = self .name )
83+ )
84+ return view (request , * args , ** kwargs )
85+ if not cacheable :
86+ inner = never_cache (inner )
87+ # We add csrf_protect here so this function can be used as a utility
88+ # function for any view, without having to repeat 'csrf_protect'.
89+ if not getattr (view , 'csrf_exempt' , False ):
90+ inner = csrf_protect (inner )
91+ return update_wrapper (inner , view )
92+
93+ @never_cache
3794 def login (self , request , extra_context = None ):
3895 """
3996 Redirects to the site login page for the given HttpRequest.
4097 If user has admin permissions but 2FA not setup, then redirect to
4198 2FA setup page.
4299 """
100+ print ("AdminSiteOTPRequiredMixin.login" )
101+
43102 # redirect to admin page after login
44103 redirect_to = request .POST .get (REDIRECT_FIELD_NAME , request .GET .get (REDIRECT_FIELD_NAME ))
104+ has_admin_access = AdminSite ().has_permission (request )
105+ print ("AdminSiteOTPRequiredMixin.login" , redirect_to , request .method , has_admin_access )
45106
46107 # if user (is_active and is_staff)
47- if request .method == "GET" and AdminSite (). has_permission ( request ) :
108+ if request .method == "GET" and has_admin_access :
48109
49110 # if user has 2FA setup, go to admin homepage
50111 if request .user .is_verified ():
112+ print ("User is verified, going to normal index." )
51113 index_path = reverse ("admin:index" , current_app = self .name )
52114
53115 # 2FA not setup. redirect to 2FA setup page
54116 else :
117+ print ("User is not verified. redirecting to two_factor setup." )
55118 index_path = reverse ("two_factor:setup" , current_app = self .name )
56119
57120 return HttpResponseRedirect (index_path )
0 commit comments