From ee855924adcf0efadc7bd44d8b804a665e8f68db Mon Sep 17 00:00:00 2001 From: realaravinth Date: Mon, 6 Jun 2022 10:11:17 +0530 Subject: [PATCH] feat: delete OAuth2.0 app view and tests --- oauth/integrations/tests.py | 104 ++++++++++++++++++++++++++++++++++++ oauth/integrations/urls.py | 1 + oauth/integrations/views.py | 21 +++++++- 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/oauth/integrations/tests.py b/oauth/integrations/tests.py index 93e3b7f..70626e4 100644 --- a/oauth/integrations/tests.py +++ b/oauth/integrations/tests.py @@ -17,6 +17,7 @@ from django.urls import reverse from django.test import TestCase, Client, override_settings from .views import CREATE_APP_CTX +from .models import OauthIntegration class CreateNewAppTests(TestCase): @@ -106,3 +107,106 @@ class CreateNewAppTests(TestCase): resp = c.get(reverse("oauth.integrations.new_app")) self.assertEqual(resp.status_code, 200) + + +class DeleteAppTest(TestCase): + """ + Tests create delete app view + """ + + def setUp(self): + self.password = "password121231" + self.user = get_user_model().objects.create_user( + username="delete_app_tests", + email="delete_app_tests@example.org", + password=self.password, + ) + + self.superuser = get_user_model().objects.create_superuser( + username="delete_app_tests_superuser", + email="delete_app_tests_superuser@example.org", + password=self.password, + ) + payload = { + "name": "test_deletebmission", + "redirect_uri": "https://test_deletebmission.example.org", + } + self.integration = OauthIntegration( + owned_by=self.superuser, + name_text=payload["name"], + redirect_uri=payload["redirect_uri"], + ) + self.integration2 = OauthIntegration( + owned_by=self.user, + name_text=payload["name"], + redirect_uri="http://test_deletebmission_2.example.org", + ) + + self.integration.save() + self.integration2.save() + self.path = reverse( + "oauth.integrations.del_app", + kwargs={"client_id": self.integration.client_id_uuid}, + ) + self.path2 = reverse( + "oauth.integrations.del_app", + kwargs={"client_id": self.integration2.client_id_uuid}, + ) + + def test_delete_app_unauthenticated_user(self): + """ + Tests if delete accessible only when user is authenticated + """ + resp = self.client.post(self.path) + self.assertEqual(resp.status_code, 302) + + def test_view_is_restricted_to_super_user(self): + """ + Tests if view is only accessible from superuser accounts + """ + c = Client() + c.login(username=self.user.username, password=self.password) + c.session.save() + + resp = c.post(self.path) + self.assertEqual(resp.status_code, 404) + + def test_delete_works(self): + """ + Tests delete works render + """ + + c = Client() + c.login(username=self.superuser.username, password=self.password) + c.session.save() + resp = c.post(self.path) + self.assertEqual(resp.status_code, 200) + + def test_method_unavailable(self): + """ + Test delete app using unsupported HTTP method + """ + c = Client() + c.login(username=self.superuser.username, password=self.password) + c.session.save() + + resp = c.head(self.path) + self.assertEqual(resp.status_code, 405) + + @override_settings(RESTRICT_NEW_INTEGRATION_INSTALLATION=False) + def test_unrestricted_app_deletion(self): + """ + Test delete app using unsupported HTTP method + """ + c = Client() + + # user != owned_by + c.login(username=self.superuser.username, password=self.password) + c.session.save() + resp = c.post(self.path2) + self.assertEqual(resp.status_code, 404) + + c.login(username=self.user.username, password=self.password) + c.session.save() + resp = c.post(self.path2) + self.assertEqual(resp.status_code, 200) diff --git a/oauth/integrations/urls.py b/oauth/integrations/urls.py index f37bb55..291e09b 100644 --- a/oauth/integrations/urls.py +++ b/oauth/integrations/urls.py @@ -19,4 +19,5 @@ from . import views urlpatterns = [ path("new/", views.new_app, name="oauth.integrations.new_app"), + path("delete//", views.del_app, name="oauth.integrations.del_app"), ] diff --git a/oauth/integrations/views.py b/oauth/integrations/views.py index bc8204e..5b60717 100644 --- a/oauth/integrations/views.py +++ b/oauth/integrations/views.py @@ -13,8 +13,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 from django.http import HttpResponse, HttpResponseNotFound +from django.views.decorators.http import require_POST from django.contrib.auth import authenticate from django.contrib.auth.decorators import login_required from django.conf import settings @@ -57,3 +58,21 @@ def new_app(request): return HttpResponse("OK") return HttpResponseNotFound("Method not supported") + + +@login_required +@csrf_protect +@require_POST +def del_app(request, client_id): + """ + Delete OAuth App + """ + if settings.RESTRICT_NEW_INTEGRATION_INSTALLATION: + if not request.user.is_superuser: + return HttpResponseNotFound("Page not Found") + + app = get_object_or_404( + OauthIntegration, client_id_uuid=client_id, owned_by=request.user + ) + app.delete() + return HttpResponse("OK")