kopia lustrzana https://github.com/wagtail/wagtail
Sanitize return_url (#6909)
rodzic
400bc57536
commit
09431f7b22
|
@ -21,6 +21,7 @@ Changelog
|
||||||
* Fix: `{% include_block with context %}` now passes local variables into the block template (Jonny Scholes)
|
* Fix: `{% include_block with context %}` now passes local variables into the block template (Jonny Scholes)
|
||||||
* Fix: Fix pagination on 'view users in a group' (Sagar Agarwal)
|
* Fix: Fix pagination on 'view users in a group' (Sagar Agarwal)
|
||||||
* Fix: Prevent page privacy menu from being triggered by pressing enter on a char field (Sagar Agarwal)
|
* Fix: Prevent page privacy menu from being triggered by pressing enter on a char field (Sagar Agarwal)
|
||||||
|
* Fix: Validate host/scheme of return URLs on password authentication forms (Susan Dreher)
|
||||||
|
|
||||||
|
|
||||||
2.12.3 (05.03.2021)
|
2.12.3 (05.03.2021)
|
||||||
|
|
|
@ -501,6 +501,7 @@ Contributors
|
||||||
* Tibor Leupold
|
* Tibor Leupold
|
||||||
* Joan Eliot
|
* Joan Eliot
|
||||||
* Sagar Agarwal
|
* Sagar Agarwal
|
||||||
|
* Susan Dreher
|
||||||
|
|
||||||
Translators
|
Translators
|
||||||
===========
|
===========
|
||||||
|
|
|
@ -40,6 +40,7 @@ Bug fixes
|
||||||
* Make image chooser "Select format" fields translatable (Helen Chapman, Thibaud Colas)
|
* Make image chooser "Select format" fields translatable (Helen Chapman, Thibaud Colas)
|
||||||
* Fix pagination on 'view users in a group' (Sagar Agarwal)
|
* Fix pagination on 'view users in a group' (Sagar Agarwal)
|
||||||
* Prevent page privacy menu from being triggered by pressing enter on a char field (Sagar Agarwal)
|
* Prevent page privacy menu from being triggered by pressing enter on a char field (Sagar Agarwal)
|
||||||
|
* Validate host/scheme of return URLs on password authentication forms (Susan Dreher)
|
||||||
|
|
||||||
|
|
||||||
Upgrade considerations
|
Upgrade considerations
|
||||||
|
|
|
@ -48,6 +48,16 @@ class TestPagePrivacy(TestCase, WagtailTestUtils):
|
||||||
response = self.client.get('/secret-plans/')
|
response = self.client.get('/secret-plans/')
|
||||||
self.assertEqual(response.templates[0].name, 'tests/simple_page.html')
|
self.assertEqual(response.templates[0].name, 'tests/simple_page.html')
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
# posting an invalid return_url will redirect to default login redirect
|
||||||
|
with self.settings(LOGIN_REDIRECT_URL='/'):
|
||||||
|
response = self.client.post(submit_url, {
|
||||||
|
'password': 'swordfish',
|
||||||
|
'return_url': 'https://invaliddomain.com',
|
||||||
|
})
|
||||||
|
self.assertRedirects(response, '/')
|
||||||
|
|
||||||
def test_view_restrictions_apply_to_subpages(self):
|
def test_view_restrictions_apply_to_subpages(self):
|
||||||
underpants_page = Page.objects.get(url_path='/home/secret-plans/steal-underpants/')
|
underpants_page = Page.objects.get(url_path='/home/secret-plans/steal-underpants/')
|
||||||
response = self.client.get('/secret-plans/steal-underpants/')
|
response = self.client.get('/secret-plans/steal-underpants/')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404, HttpResponse
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
@ -7,6 +8,12 @@ from wagtail.core.forms import PasswordViewRestrictionForm
|
||||||
from wagtail.core.models import Page, PageViewRestriction, Site
|
from wagtail.core.models import Page, PageViewRestriction, Site
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.utils.http import url_has_allowed_host_and_scheme
|
||||||
|
except ImportError: # fallback for Django 2.2
|
||||||
|
from django.utils.http import is_safe_url as url_has_allowed_host_and_scheme
|
||||||
|
|
||||||
|
|
||||||
def serve(request, path):
|
def serve(request, path):
|
||||||
# we need a valid Site object corresponding to this request in order to proceed
|
# we need a valid Site object corresponding to this request in order to proceed
|
||||||
site = Site.find_for_request(request)
|
site = Site.find_for_request(request)
|
||||||
|
@ -35,9 +42,13 @@ def authenticate_with_password(request, page_view_restriction_id, page_id):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = PasswordViewRestrictionForm(request.POST, instance=restriction)
|
form = PasswordViewRestrictionForm(request.POST, instance=restriction)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
restriction.mark_as_passed(request)
|
return_url = form.cleaned_data['return_url']
|
||||||
|
|
||||||
return redirect(form.cleaned_data['return_url'])
|
if not url_has_allowed_host_and_scheme(return_url, request.get_host(), request.is_secure()):
|
||||||
|
return_url = settings.LOGIN_REDIRECT_URL
|
||||||
|
|
||||||
|
restriction.mark_as_passed(request)
|
||||||
|
return redirect(return_url)
|
||||||
else:
|
else:
|
||||||
form = PasswordViewRestrictionForm(instance=restriction)
|
form = PasswordViewRestrictionForm(instance=restriction)
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,16 @@ class TestCollectionPrivacyDocument(TestCase, WagtailTestUtils):
|
||||||
# now requests to the documents url should pass authentication
|
# now requests to the documents url should pass authentication
|
||||||
response = self.client.get(doc_url)
|
response = self.client.get(doc_url)
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
# posting an invalid return_url will redirect to default login redirect
|
||||||
|
with self.settings(LOGIN_REDIRECT_URL='/'):
|
||||||
|
response = self.client.post(submit_url, {
|
||||||
|
'password': 'swordfish',
|
||||||
|
'return_url': 'https://invaliddomain.com',
|
||||||
|
})
|
||||||
|
self.assertRedirects(response, '/')
|
||||||
|
|
||||||
def test_group_restriction_with_anonymous_user(self):
|
def test_group_restriction_with_anonymous_user(self):
|
||||||
response, url = self.get_document(self.group_collection)
|
response, url = self.get_document(self.group_collection)
|
||||||
self.assertRedirects(response, '/_util/login/?next={}'.format(url))
|
self.assertRedirects(response, '/_util/login/?next={}'.format(url))
|
||||||
|
|
|
@ -17,6 +17,12 @@ from wagtail.utils import sendfile_streaming_backend
|
||||||
from wagtail.utils.sendfile import sendfile
|
from wagtail.utils.sendfile import sendfile
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.utils.http import url_has_allowed_host_and_scheme
|
||||||
|
except ImportError: # fallback for Django 2.2
|
||||||
|
from django.utils.http import is_safe_url as url_has_allowed_host_and_scheme
|
||||||
|
|
||||||
|
|
||||||
def document_etag(request, document_id, document_filename):
|
def document_etag(request, document_id, document_filename):
|
||||||
Document = get_document_model()
|
Document = get_document_model()
|
||||||
if hasattr(Document, 'file_hash'):
|
if hasattr(Document, 'file_hash'):
|
||||||
|
@ -120,9 +126,13 @@ def authenticate_with_password(request, restriction_id):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = PasswordViewRestrictionForm(request.POST, instance=restriction)
|
form = PasswordViewRestrictionForm(request.POST, instance=restriction)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
restriction.mark_as_passed(request)
|
return_url = form.cleaned_data['return_url']
|
||||||
|
|
||||||
return redirect(form.cleaned_data['return_url'])
|
if not url_has_allowed_host_and_scheme(return_url, request.get_host(), request.is_secure()):
|
||||||
|
return_url = settings.LOGIN_REDIRECT_URL
|
||||||
|
|
||||||
|
restriction.mark_as_passed(request)
|
||||||
|
return redirect(return_url)
|
||||||
else:
|
else:
|
||||||
form = PasswordViewRestrictionForm(instance=restriction)
|
form = PasswordViewRestrictionForm(instance=restriction)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue