mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
The user edit page redirected to its ?next= parameter after saving, whatever it held: a link to the edit page with next=https://other.site sent the administrator who saved the form to that site (CodeQL py/url-redirection). The account page links there with a next of this site. next is now followed only when url_has_allowed_host_and_scheme accepts it for this host, as user_instance_delete already does; otherwise the user list. The test fails on the previous code for an absolute URL, a scheme-relative one and a backslash variant.
26 lines
1.2 KiB
Python
26 lines
1.2 KiB
Python
"""After saving a user, the edit page goes back to ?next= only on this site."""
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
|
|
LIMITS = {"max_instances": 1, "max_cpus": 1, "max_memory": 1024, "max_disk_size": 4}
|
|
|
|
|
|
class UserUpdateNextTests(TestCase):
|
|
def setUp(self):
|
|
self.client.force_login(User.objects.create_superuser("un-admin", "un@example.com", "pw"))
|
|
self.user = User.objects.create_user("un-user", password="pw")
|
|
|
|
def save(self, next_url):
|
|
url = reverse("admin:user_update", args=[self.user.id]) + "?next=" + next_url
|
|
return self.client.post(url, {"username": "un-user", "is_active": "on", **LIMITS})
|
|
|
|
def test_a_page_of_this_site(self):
|
|
account = reverse("accounts:account", args=[self.user.id])
|
|
self.assertRedirects(self.save(account), account, fetch_redirect_response=False)
|
|
|
|
def test_another_site_is_not_followed(self):
|
|
for next_url in ("https://evil.example/", "//evil.example/", "/\\evil.example/"):
|
|
with self.subTest(next_url=next_url):
|
|
self.assertRedirects(self.save(next_url), reverse("admin:user_list"), fetch_redirect_response=False)
|