From 37a93e82558f839a7ba1f9cfaa1ff413e35bc198 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Mon, 2 Jun 2025 15:25:37 +0200 Subject: [PATCH] Allow superusers to bypass pattern based permissions To avoid having to explicitlyg rant wildcard permissions across all existing domains... --- pgmailmgr/mailmgr/forms.py | 46 ++++++++++++++++++++------------------ pgmailmgr/mailmgr/views.py | 17 ++++++++++---- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/pgmailmgr/mailmgr/forms.py b/pgmailmgr/mailmgr/forms.py index 2b6521a..a3c59b7 100644 --- a/pgmailmgr/mailmgr/forms.py +++ b/pgmailmgr/mailmgr/forms.py @@ -112,17 +112,18 @@ class VirtualUserForm(forms.ModelForm): if 'local_domain' not in self.cleaned_data: return {} - # Validate that the pattern is allowed - curs = connection.cursor() - curs.execute("SELECT 1 FROM mailmgr_userpermissions WHERE user_id=%(uid)s AND domain_id=%(domain)s AND %(lp)s ~* ('^'||pattern||'$')", { - 'uid': self.user.pk, - 'domain': self.cleaned_data['local_domain'].pk, - 'lp': self.cleaned_data['local_part'], - }) - perms = curs.fetchall() - - if len(perms) < 1: - raise ValidationError("Permission denied to create that user for that domain!") + if not self.user.is_superuser: + # Validate that the pattern is allowed + curs = connection.cursor() + curs.execute("SELECT 1 FROM mailmgr_userpermissions WHERE user_id=%(uid)s AND domain_id=%(domain)s AND %(lp)s ~* ('^'||pattern||'$')", { + 'uid': self.user.pk, + 'domain': self.cleaned_data['local_domain'].pk, + 'lp': self.cleaned_data['local_part'], + }) + perms = curs.fetchall() + + if len(perms) < 1: + raise ValidationError("Permission denied to create that user for that domain!") # If it's a new user, also check against if it already exists if not self.instance.pk: @@ -167,17 +168,18 @@ class ForwarderForm(forms.ModelForm): if 'local_domain' not in self.cleaned_data: return {} - # Validate that the pattern is allowed - curs = connection.cursor() - curs.execute("SELECT 1 FROM mailmgr_userpermissions WHERE user_id=%(uid)s AND domain_id=%(domain)s AND %(lp)s ~* ('^'||pattern||'$')", { - 'uid': self.user.pk, - 'domain': self.cleaned_data['local_domain'].pk, - 'lp': self.cleaned_data['local_part'], - }) - perms = curs.fetchall() - - if len(perms) < 1: - raise ValidationError("Permission denied to create that forwarder for that domain!") + if not self.user.is_superuser: + # Validate that the pattern is allowed + curs = connection.cursor() + curs.execute("SELECT 1 FROM mailmgr_userpermissions WHERE user_id=%(uid)s AND domain_id=%(domain)s AND %(lp)s ~* ('^'||pattern||'$')", { + 'uid': self.user.pk, + 'domain': self.cleaned_data['local_domain'].pk, + 'lp': self.cleaned_data['local_part'], + }) + perms = curs.fetchall() + + if len(perms) < 1: + raise ValidationError("Permission denied to create that forwarder for that domain!") # If it's a new user, also check against if it already exists if not self.instance.pk: diff --git a/pgmailmgr/mailmgr/views.py b/pgmailmgr/mailmgr/views.py index 343bdb1..85ef75d 100644 --- a/pgmailmgr/mailmgr/views.py +++ b/pgmailmgr/mailmgr/views.py @@ -1,5 +1,5 @@ from django.shortcuts import render, get_object_or_404 -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, Http404 from django.contrib.auth.decorators import login_required from django.contrib import messages from django.db import transaction @@ -18,7 +18,8 @@ def log(user, what): @login_required def home(request): - admperm = VirtualUser.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]).exists() or \ + admperm = request.user.is_superuser or \ + VirtualUser.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]).exists() or \ Forwarder.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]).exists() mailboxes = VirtualUser.objects.filter(account=request.user.id) @@ -55,8 +56,12 @@ def mailbox(request, virtualid): @login_required def adm_home(request): - users = VirtualUser.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) - forwards = Forwarder.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) + if request.user.is_superuser: + users = VirtualUser.objects.all() + forwards = Forwarder.objects.all() + else: + users = VirtualUser.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) + forwards = Forwarder.objects.extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) if not forwards and not users: return render(request, 'noadm.html', { @@ -73,6 +78,8 @@ def adm_home(request): def userform(request, userparam): if userparam == 'add': vu = VirtualUser() + elif request.user.is_superuser: + vu = get_object_or_404(VirtualUser, pk=userparam) else: vulist = VirtualUser.objects.filter(pk=userparam).extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) if len(vulist) != 1: @@ -110,6 +117,8 @@ def userform(request, userparam): def forwarderform(request, userparam): if userparam == 'add': fwd = Forwarder() + elif request.user.is_superuser: + fwd = get_object_or_404(Forwarder, pk=userparam) else: fwdlist = Forwarder.objects.filter(pk=userparam).extra(where=["EXISTS (SELECT 1 FROM mailmgr_userpermissions p WHERE p.user_id=%s AND p.domain_id = local_domain_id AND local_part ~* ('^'||p.pattern||'$'))" % request.user.id]) if len(fwdlist) != 1: -- 2.39.5