diff --git a/dashboard/settings.py b/dashboard/settings.py
index f1462a4..0a997f1 100644
--- a/dashboard/settings.py
+++ b/dashboard/settings.py
@@ -126,3 +126,8 @@ STATIC_URL = "static/"
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+
+### Dashbaord specific configuration options
+
+RESTRICT_NEW_INTEGRATION_INSTALLATION = True
diff --git a/oauth/integrations/migrations/0009_alter_oauthintegration_client_secret_text.py b/oauth/integrations/migrations/0009_alter_oauthintegration_client_secret_text.py
new file mode 100644
index 0000000..fd4c237
--- /dev/null
+++ b/oauth/integrations/migrations/0009_alter_oauthintegration_client_secret_text.py
@@ -0,0 +1,25 @@
+# Generated by Django 4.0.3 on 2022-06-06 03:45
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("integrations", "0008_alter_oauthintegration_client_secret_text_and_more"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="oauthintegration",
+ name="client_secret_text",
+ field=models.CharField(
+ blank=True,
+ default="driw0y2clz6sqnNFYE62Okl6NPW51XHt",
+ editable=False,
+ max_length=32,
+ unique=True,
+ verbose_name="client secret",
+ ),
+ ),
+ ]
diff --git a/oauth/integrations/tests.py b/oauth/integrations/tests.py
index f083d18..93e3b7f 100644
--- a/oauth/integrations/tests.py
+++ b/oauth/integrations/tests.py
@@ -12,13 +12,11 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-
-
from django.contrib.auth import get_user_model
from django.urls import reverse
-from django.test import TestCase, Client
+from django.test import TestCase, Client, override_settings
-from .views import CREATE_APP_CTX, new_app
+from .views import CREATE_APP_CTX
class CreateNewAppTests(TestCase):
@@ -34,6 +32,12 @@ class CreateNewAppTests(TestCase):
password=self.password,
)
+ self.superuser = get_user_model().objects.create_superuser(
+ username="create_new_app_tests_superuser",
+ email="create_new_app_tests_superuser@example.org",
+ password=self.password,
+ )
+
def test_create_new_app_unauthenticated_user(self):
"""
Tests if new_app is accessible only when user is authenticated
@@ -41,13 +45,24 @@ class CreateNewAppTests(TestCase):
resp = self.client.get(reverse("oauth.integrations.new_app"))
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.get(reverse("oauth.integrations.new_app"))
+ self.assertEqual(resp.status_code, 404)
+
def test_create_new_app_renders(self):
"""
Tests new_app template render
"""
c = Client()
- c.login(username=self.user.username, password=self.password)
+ c.login(username=self.superuser.username, password=self.password)
c.session.save()
resp = c.get(reverse("oauth.integrations.new_app"))
@@ -64,7 +79,30 @@ class CreateNewAppTests(TestCase):
"redirect_uri": "https://test_new_app_submission.example.org",
}
c = Client()
- c.login(username=self.user.username, password=self.password)
+ c.login(username=self.superuser.username, password=self.password)
c.session.save()
resp = c.post(reverse("oauth.integrations.new_app"), payload)
self.assertEqual(resp.status_code, 200)
+
+ def test_method_unavailable(self):
+ """
+ Test new_app using unsupported HTTP method
+ """
+ c = Client()
+ c.login(username=self.superuser.username, password=self.password)
+ c.session.save()
+
+ resp = c.head(reverse("oauth.integrations.new_app"))
+ self.assertEqual(resp.status_code, 404)
+
+ @override_settings(RESTRICT_NEW_INTEGRATION_INSTALLATION=False)
+ def test_unrestricted_app_creation(self):
+ """
+ Test new_app using unsupported HTTP method
+ """
+ c = Client()
+ c.login(username=self.user.username, password=self.password)
+ c.session.save()
+
+ resp = c.get(reverse("oauth.integrations.new_app"))
+ self.assertEqual(resp.status_code, 200)
diff --git a/oauth/integrations/views.py b/oauth/integrations/views.py
index 80874a4..bc8204e 100644
--- a/oauth/integrations/views.py
+++ b/oauth/integrations/views.py
@@ -14,9 +14,10 @@
# along with this program. If not, see .
from django.shortcuts import render
-from django.http import HttpResponse, Http404
+from django.http import HttpResponse, HttpResponseNotFound
from django.contrib.auth import authenticate
from django.contrib.auth.decorators import login_required
+from django.conf import settings
from django.views.decorators.csrf import csrf_protect
@@ -36,6 +37,10 @@ def new_app(request):
"""
Create new OAuth integration APP
"""
+ if settings.RESTRICT_NEW_INTEGRATION_INSTALLATION:
+ if not request.user.is_superuser:
+ return HttpResponseNotFound("Page not Found")
+
if request.method == "GET":
return render(request, "integrations/new.html", {"create_app": CREATE_APP_CTX})
@@ -48,8 +53,7 @@ def new_app(request):
if "privacy_policy" in request.POST:
app.privacy_policy_uri = request.POST["privacy_policy"]
- print("OK")
app.save()
return HttpResponse("OK")
- return Http404("Method not supported")
+ return HttpResponseNotFound("Method not supported")
diff --git a/oauth/migrations/0009_alter_authorizationgrant_code_text.py b/oauth/migrations/0009_alter_authorizationgrant_code_text.py
new file mode 100644
index 0000000..140a256
--- /dev/null
+++ b/oauth/migrations/0009_alter_authorizationgrant_code_text.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.0.3 on 2022-06-06 03:45
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("oauth", "0008_alter_authorizationgrant_code_text"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="authorizationgrant",
+ name="code_text",
+ field=models.CharField(
+ blank=True,
+ default="CwLC9yHqvoQh9pHWQbQyqCqTEZlugZZa",
+ editable=False,
+ max_length=32,
+ primary_key=True,
+ serialize=False,
+ unique=True,
+ verbose_name="Authorization Code",
+ ),
+ ),
+ ]