Quellcode durchsuchen

Require HTTPS for user-account-related pages.

Andrew Klopper vor 8 Jahren
Ursprung
Commit
4c0f95e59d
3 geänderte Dateien mit 35 neuen und 9 gelöschten Zeilen
  1. 25 0
      accounts/decorators.py
  2. 9 8
      accounts/urls.py
  3. 1 1
      accounts/viewsets.py

+ 25 - 0
accounts/decorators.py

1
+from functools import wraps
2
+from django.http import HttpResponseRedirect
1
 from django.contrib.auth.decorators import user_passes_test
3
 from django.contrib.auth.decorators import user_passes_test
2
 from django.conf import settings
4
 from django.conf import settings
3
 
5
 
4
 superuser_required = user_passes_test(lambda u: u.is_superuser, login_url=settings.LOGIN_URL)
6
 superuser_required = user_passes_test(lambda u: u.is_superuser, login_url=settings.LOGIN_URL)
7
+
8
+def https_required(view):
9
+    """A view decorator that redirects to HTTPS if this view is requested
10
+    over HTTP. Allows HTTP when DEBUG is on and during unit tests.
11
+    """
12
+    @wraps(view)
13
+    def view_or_redirect(request, *args, **kwargs):
14
+        if not request.is_secure():
15
+            # Just load the view on a devserver or in the testing environment.
16
+            if settings.DEBUG or request.META['SERVER_NAME'] == "testserver":
17
+                return view(request, *args, **kwargs)
18
+            else:
19
+                # Redirect to HTTPS.
20
+                request_url = request.build_absolute_uri(request.get_full_path())
21
+                secure_url = request_url.replace('http://', 'https://')
22
+                return HttpResponseRedirect(secure_url)
23
+        else:
24
+            # It's HTTPS, so load the view.
25
+            return view(request, *args, **kwargs)
26
+    return view_or_redirect
27
+
28
+def https_and_superuser_required(view):
29
+    return https_required(superuser_required(view))

+ 9 - 8
accounts/urls.py

1
 from django.conf.urls import url, include
1
 from django.conf.urls import url, include
2
 from django.contrib.auth import views as auth_views
2
 from django.contrib.auth import views as auth_views
3
+from .decorators import https_required
3
 from . import views, viewsets
4
 from . import views, viewsets
4
 
5
 
5
 urlpatterns = [
6
 urlpatterns = [
6
-    url(r'^login/$', views.RememberMeLoginView.as_view(), name='login'),
7
-    url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
8
-    url(r'^password_change/$', auth_views.PasswordChangeView.as_view(), name='password_change'),
9
-    url(r'^password_change/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
10
-    url(r'^password_reset/$', auth_views.PasswordResetView.as_view(), name='password_reset'),
11
-    url(r'^password_reset/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_reset_done'),
12
-    url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
13
-    url(r'^reset/done/$', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
7
+    url(r'^login/$', https_required(views.RememberMeLoginView.as_view()), name='login'),
8
+    url(r'^logout/$', https_required(auth_views.LogoutView.as_view()), name='logout'),
9
+    url(r'^password_change/$', https_required(auth_views.PasswordChangeView.as_view()), name='password_change'),
10
+    url(r'^password_change/done/$', https_required(auth_views.PasswordChangeDoneView.as_view()), name='password_change_done'),
11
+    url(r'^password_reset/$', https_required(auth_views.PasswordResetView.as_view()), name='password_reset'),
12
+    url(r'^password_reset/done/$', https_required(auth_views.PasswordChangeDoneView.as_view()), name='password_reset_done'),
13
+    url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', https_required(auth_views.PasswordResetConfirmView.as_view()), name='password_reset_confirm'),
14
+    url(r'^reset/done/$', https_required(auth_views.PasswordResetCompleteView.as_view()), name='password_reset_complete'),
14
     url(r'^users/', include(viewsets.UserViewset.urls(), namespace='user')),
15
     url(r'^users/', include(viewsets.UserViewset.urls(), namespace='user')),
15
 ]
16
 ]

+ 1 - 1
accounts/viewsets.py

76
         return user
76
         return user
77
 
77
 
78
 class UserViewset(BaseViewset):
78
 class UserViewset(BaseViewset):
79
-    view_decorator = staticmethod(decorators.superuser_required)
79
+    view_decorator = staticmethod(decorators.https_and_superuser_required)
80
 
80
 
81
     filter_class = UserFilterSet
81
     filter_class = UserFilterSet
82
     form_class = UserForm
82
     form_class = UserForm