Do not set permissions on internal aliases.

This commit is contained in:
Antoine Nguyen
2025-11-13 15:32:25 +01:00
parent 073cbe0b83
commit 5bafa6a92f
8 changed files with 62 additions and 25 deletions
+19 -5
View File
@@ -192,6 +192,18 @@ class AccountViewSet(
return Response(body)
class AliasFilter(dj_filters.FilterSet):
domain = dj_filters.ModelChoiceFilter(
queryset=lambda request: models.Domain.objects.get_for_admin(request.user),
field_name="mailbox__domain",
)
class Meta:
model = models.Alias
fields = ["domain"]
class AliasViewSet(
GetThrottleViewsetMixin, lib_viewsets.RevisionModelMixin, viewsets.ModelViewSet
):
@@ -200,6 +212,10 @@ class AliasViewSet(
Create a new alias instance.
"""
filter_backends = [
dj_filters.DjangoFilterBackend,
]
filterset_class = AliasFilter
permission_classes = [
IsAuthenticated,
DjangoModelPermissions,
@@ -209,14 +225,12 @@ class AliasViewSet(
def get_queryset(self):
"""Filter queryset based on current user."""
user = self.request.user
if user is None or user.is_anonymous:
return models.Alias.objects.none()
ids = user.objectaccess_set.filter(
content_type=ContentType.objects.get_for_model(models.Alias)
).values_list("object_id", flat=True)
queryset = models.Alias.objects.filter(pk__in=ids)
domain = self.request.query_params.get("domain")
if domain:
queryset = queryset.filter(domain__name=domain)
return queryset
return models.Alias.objects.filter(pk__in=ids, internal=False)
class SenderAddressFilterSet(dj_filters.FilterSet):
+2 -1
View File
@@ -521,7 +521,8 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
if not param_tools.get_global_parameter("enable_admin_limits", app="limits"):
return
del self.fields["domains"]
if self.context["request"].user.role in ["Resellers", "SuperAdmins"]:
user = self.context["request"].user
if not user.is_anonymous and user.role in ["Resellers", "SuperAdmins"]:
self.fields["resources"] = WritableResourceSerializer(
many=True, required=False
)
+23 -4
View File
@@ -74,7 +74,9 @@ class DomainViewSet(
def get_queryset(self):
"""Filter queryset based on current user."""
return models.Domain.objects.get_for_admin(self.request.user)
if self.request.user and not self.request.user.is_anonymous:
return models.Domain.objects.get_for_admin(self.request.user)
return models.Domain.objects.none()
def get_serializer_class(self, *args, **kwargs):
if self.action == "delete":
@@ -198,6 +200,8 @@ class AccountViewSet(v1_viewsets.AccountViewSet):
def get_queryset(self):
"""Filter queryset based on current user."""
user = self.request.user
if not user or user.is_anonymous:
return core_models.User.objects.none()
ids = user.objectaccess_set.filter(
content_type=ContentType.objects.get_for_model(user)
).values_list("object_id", flat=True)
@@ -271,14 +275,27 @@ class IdentityViewSet(GetThrottleViewsetMixin, viewsets.ViewSet):
return response.Response({"status": status, "message": msg})
class AliasFilter(dj_filters.FilterSet):
domain = dj_filters.ModelChoiceFilter(
queryset=lambda request: models.Domain.objects.get_for_admin(request.user),
field_name="domain__name",
)
class Meta:
model = models.Alias
fields = ["domain"]
class AliasViewSet(v1_viewsets.AliasViewSet):
"""Viewset for Alias."""
filter_backends = (
filter_backends = [
dj_filters.DjangoFilterBackend,
filters.OrderingFilter,
filters.SearchFilter,
dj_filters.DjangoFilterBackend,
)
]
filterset_class = AliasFilter
pagination_class = pagination.CustomPageNumberPagination
search_fields = ["address"]
serializer_class = serializers.AliasSerializer
@@ -391,6 +408,8 @@ class AlarmViewSet(
serializer_class = serializers.AlarmSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return models.Alarm.objects.none()
return (
models.Alarm.objects.select_related("domain")
.filter(domain__in=models.Domain.objects.get_for_admin(self.request.user))
+8 -13
View File
@@ -236,11 +236,6 @@ def import_account_mailbox(sender, user, account, row, **kwargs):
sender="import", context=domain, object_type="mailboxes"
)
account.save()
qset = models.Mailbox.objects.filter(address=mailbox, domain=domain)
if qset.exists():
raise exceptions.Conflict(
_("Mailbox {} already exists").format(account.email)
)
if len(row) == 1:
quota = None
else:
@@ -274,16 +269,16 @@ def grant_access_to_all_objects(sender, account, role, **kwargs):
"""Grant all permissions if new role is SuperAdmin."""
if role != "SuperAdmins":
return
perm_models = [
core_models.User,
models.Domain,
models.DomainAlias,
models.Mailbox,
models.Alias,
querysets = [
core_models.User.objects.all(),
models.Domain.objects.all(),
models.DomainAlias.objects.all(),
models.Mailbox.objects.all(),
models.Alias.objects.filter(internal=False),
]
for model in perm_models:
for queryset in querysets:
permissions.grant_access_to_objects(
account, model.objects.all(), ContentType.objects.get_for_model(model)
account, queryset, ContentType.objects.get_for_model(queryset.model)
)
@@ -56,7 +56,7 @@ def sometimes_objects_have_no_owner(**options):
User.objects.all(),
models.Domain.objects.all(),
models.DomainAlias.objects.all(),
models.Alias.objects.filter(domain__isnull=False),
models.Alias.objects.filter(internal=False, domain__isnull=False),
models.Mailbox.objects.filter(domain__isnull=False),
)
for qs in owned_models:
+1 -1
View File
@@ -257,7 +257,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
continue
grant_access_to_object(account, mb)
grant_access_to_object(account, mb.user)
for al in self.alias_set.all():
for al in self.alias_set.filter(internal=False):
grant_access_to_object(account, al)
def remove_admin(self, account):
@@ -71,6 +71,7 @@ INSTALLED_APPS = (
'corsheaders',
'rest_framework',
'rest_framework.authtoken',
'django_filters',
'drf_spectacular',
'phonenumber_field',
'django_otp',
@@ -246,6 +247,9 @@ SPECTACULAR_SETTINGS = {
'TITLE': 'Modoboa API',
'VERSION': None,
'SERVE_AUTHENTICATION': [],
'DEFAULT_FILTER_INSPECTORS': [
'drf_spectacular.contrib.django_filters.DjangoFilterBackendInspector',
],
}
# Modoboa settings
+4
View File
@@ -79,6 +79,7 @@ INSTALLED_APPS = (
"corsheaders",
"rest_framework",
"rest_framework.authtoken",
"django_filters",
"drf_spectacular",
"django_otp",
"django_otp.plugins.otp_totp",
@@ -262,6 +263,9 @@ SPECTACULAR_SETTINGS = {
"TITLE": "Modoboa API",
"VERSION": None,
"SERVE_AUTHENTICATION": [],
"DEFAULT_FILTER_INSPECTORS": [
"drf_spectacular.contrib.django_filters.DjangoFilterBackendInspector",
],
}
# Modoboa settings