|
|
@@ -651,3 +651,32 @@ class ProtectedObjectsMessageTestCase(TestCase):
|
|
|
'_confirm': True,
|
|
|
})
|
|
|
self.assertProtectedObjectsMessage(response)
|
|
|
+
|
|
|
+
|
|
|
+class ObjectDeleteReturnURLTestCase(TestCase):
|
|
|
+ """
|
|
|
+ After deleting an object, the delete view must redirect only to a local return URL. (Ref: #23583)
|
|
|
+ """
|
|
|
+
|
|
|
+ def setUp(self):
|
|
|
+ super().setUp()
|
|
|
+ self.add_permissions('dcim.view_site', 'dcim.delete_site')
|
|
|
+ self.site = Site.objects.create(name='Site 1', slug='site-1')
|
|
|
+ self.url = reverse('dcim:site_delete', kwargs={'pk': self.site.pk})
|
|
|
+
|
|
|
+ def test_unsafe_return_url_ignored(self):
|
|
|
+ for return_url in ('//example.com', '/\\example.com'):
|
|
|
+ with self.subTest(return_url=return_url):
|
|
|
+ site = Site.objects.create(name=f'Site {return_url}', slug='site-unsafe')
|
|
|
+ url = reverse('dcim:site_delete', kwargs={'pk': site.pk})
|
|
|
+ response = self.client.post(url, data={'confirm': True, 'return_url': return_url})
|
|
|
+ self.assertHttpStatus(response, 302)
|
|
|
+ self.assertEqual(response['Location'], reverse('dcim:site_list'))
|
|
|
+ self.assertFalse(Site.objects.filter(pk=site.pk).exists())
|
|
|
+
|
|
|
+ def test_local_return_url_followed(self):
|
|
|
+ return_url = reverse('dcim:region_list')
|
|
|
+ response = self.client.post(self.url, data={'confirm': True, 'return_url': return_url})
|
|
|
+ self.assertHttpStatus(response, 302)
|
|
|
+ self.assertEqual(response['Location'], return_url)
|
|
|
+ self.assertFalse(Site.objects.filter(pk=self.site.pk).exists())
|