diff --git a/SAS/TMSS/src/tmss/tmssapp/viewsets/permissions.py b/SAS/TMSS/src/tmss/tmssapp/viewsets/permissions.py
index 1179bc5ec2ece1c57719aba222b74036f746f85a..3e68aeba65f43de96852b093d3c05f289fb4329f 100644
--- a/SAS/TMSS/src/tmss/tmssapp/viewsets/permissions.py
+++ b/SAS/TMSS/src/tmss/tmssapp/viewsets/permissions.py
@@ -8,7 +8,6 @@ from .. import serializers
 from .lofar_viewset import LOFARViewSet
 from lofar.sas.tmss.tmss.exceptions import *
 from django.core.exceptions import ObjectDoesNotExist
-from rest_framework.permissions import DjangoModelPermissions
 import logging
 logger = logging.getLogger(__name__)
 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
@@ -36,7 +35,6 @@ class ProjectPermissionViewSet(LOFARViewSet):
 #       A. apply a filter to prevent object without permission to be included in the list with full details, or
 #       B. customize get_queryset on the view to call check_object_permissions.
 
-
 def get_project_roles_for_user(user):
 
         # todo: this set of project/role pairs needs to be provided by the OIDC federation and will probably enter TMSS
@@ -53,7 +51,7 @@ def get_project_roles_for_user(user):
             if user == models.User.objects.get(username='paulus'):
                 return ({'project': 'test_user_is_shared_support', 'role': 'shared_support_user'},
                         {'project': 'test_user_is_contact', 'role': 'contact_author'},
-                        {'project': 'high', 'role': 'contact_author'})
+                        {'project': 'high', 'role': 'shared_support_user'})
         except:
             pass
 
@@ -84,10 +82,12 @@ class IsProjectMember(drf_permissions.DjangoObjectPermissions):
         # we always have permission as superuser (e.g. in test environment, where a regular user is created to test permission specifically)
         if request.user.is_superuser:
             logger.info("IsProjectMember: User=%s is superuser. Not enforcing project permissions!" % request.user)
+            logger.info('### IsProjectMember.has_object_permission %s %s True' % (request._request, request.method))
             return True
 
-        # todo: do we want to marshal permissions for that as well? Then we add it to the ProjectPermission model, but it seems cumbersome...?
+        # todo: do we want to restrict access for that as well? Then we add it to the ProjectPermission model, but it seems cumbersome...?
         if request.method == 'OPTIONS':
+            logger.info('### IsProjectMember.has_object_permission %s %s True' % (request._request, request.method))
             return True
 
         # determine which roles are allowed to access this object...
@@ -112,9 +112,11 @@ class IsProjectMember(drf_permissions.DjangoObjectPermissions):
             if project_role['project'] == obj.project.name and \
                     models.ProjectRole.objects.get(value=project_role['role']) in permitted_project_roles:
                 logger.info('user=%s is permitted to access object=%s' % (request.user, obj))
+                logger.info('### IsProjectMember.has_object_permission %s %s True' % (request._request, request.method))
                 return True
 
         logger.info('User=%s is not permitted to access object=%s with related project=%s since it requires one of project_roles=%s' % (request.user, obj, obj.project, permitted_project_roles))
+        logger.info('### IsProjectMember.has_object_permission %s False' % (request._request))
         return False
 
     def has_permission(self, request, view):
@@ -135,11 +137,18 @@ class IsProjectMember(drf_permissions.DjangoObjectPermissions):
                     if attr == 'project':
                         # has_object_permission checks the project from obj, so we can just check project permission on
                         # something that has the correct project attribute
-                        return self.has_object_permission(request, view, obj)
+                        p=self.has_object_permission(request, view, obj)
+                        logger.info('### IsProjectMember.has_permission %s %s' % (request._request, p))
+                        return p
                     obj = getattr(obj, attr)
-        else:
-            logger.debug('allowing empty POST or non-POST request %s %s' % (request.method, view.action))
-            return True  # has_object_permission is called on get detail nonetheless
+        if view.action == 'list':
+            logger.info('Allowing list action %s %s' % (request.method, view.action))
+            logger.info('### IsProjectMember.has_permission %s %s True' % (request._request, request.method))
+            return True
+
+        logger.info('Allowing empty POST or non-POST request %s %s' % (request.method, view.action))
+        logger.info('### IsProjectMember.has_permission %s %s True' % (request._request, request.method))
+        return True
 
 
 class IsProjectMemberOrReadOnly(IsProjectMember):
@@ -159,6 +168,43 @@ class IsProjectMemberOrReadOnly(IsProjectMember):
             return super().has_object_permission(request, view, obj)
 
 
+class TMSSDjangoModelPermissions(drf_permissions.DjangoModelPermissions):
+    """
+    Modify the vanilla DjangoModelPermissions, which are apparently readonly by default
+    """
+    view_permissions = ['%(app_label)s.view_%(model_name)s']
+    perms_map = {
+        'GET': view_permissions,
+        'OPTIONS': view_permissions,
+        'HEAD': view_permissions,
+        'POST': drf_permissions.DjangoModelPermissions.perms_map['POST'],
+        'PUT': drf_permissions.DjangoModelPermissions.perms_map['PUT'],
+        'PATCH': drf_permissions.DjangoModelPermissions.perms_map['PATCH'],
+        'DELETE': drf_permissions.DjangoModelPermissions.perms_map['DELETE'],
+    }
+
+    def has_permission(self, request, view):
+        p = super().has_permission(request, view)
+        logger.info('### TMSSDjangoModelPermissions.has_permission %s %s' % (request._request, p))
+        return p
+
+
+class TMSSPermissions(drf_permissions.DjangoObjectPermissions):
+        """
+        Create custom permission class
+        Note: required because the composition using & and | in the permission_classes does not seem to work as it should.
+        """
+        model_permissions = TMSSDjangoModelPermissions()
+        project_permissions = IsProjectMember()
+
+        def has_permission(self, request, view):
+            return (self.model_permissions.has_permission(request, view) or
+                    self.project_permissions.has_permission(request, view)) and request.user.is_authenticated
+
+        def has_object_permission(self, request, view, obj):
+            return IsProjectMember().has_object_permission(request, view, obj) and request.user.is_authenticated
+
+
 #
 # Custom Filters
 #
diff --git a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
index 9df5c7644524908c25ad74f67972df38044bdae7..55333fa71af5021092ccbae465e89b1c9d06a8dc 100644
--- a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
+++ b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
@@ -13,14 +13,14 @@ from rest_framework import status
 from rest_framework.response import Response
 
 from rest_framework.decorators import permission_classes
-from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
+from rest_framework.permissions import IsAuthenticated
 from rest_framework.decorators import action
 
 from drf_yasg.utils import swagger_auto_schema
 from drf_yasg.openapi import Parameter
 
 from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOFARNestedViewSet, AbstractTemplateViewSet, LOFARCopyViewSet
-from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import IsProjectMemberFilterBackend, IsProjectMember, IsProjectMemberOrReadOnly
+from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import IsProjectMemberFilterBackend, IsProjectMember, IsProjectMemberOrReadOnly, TMSSDjangoModelPermissions, TMSSPermissions
 from lofar.sas.tmss.tmss.tmssapp import models
 from lofar.sas.tmss.tmss.tmssapp import serializers
 from django.http import JsonResponse
@@ -231,7 +231,7 @@ class TaskConnectorTypeViewSet(LOFARViewSet):
     serializer_class = serializers.TaskConnectorTypeSerializer
 
 
-@permission_classes((DjangoModelPermissions,))
+@permission_classes((TMSSDjangoModelPermissions,))
 class CycleViewSet(LOFARViewSet):
     queryset = models.Cycle.objects.all()
     serializer_class = serializers.CycleSerializer
@@ -253,7 +253,7 @@ class CycleQuotaViewSet(LOFARViewSet):
         return queryset
 
 
-@permission_classes((DjangoModelPermissions,))
+@permission_classes((TMSSDjangoModelPermissions,))
 class ProjectViewSet(LOFARViewSet):
     queryset = models.Project.objects.all()
     serializer_class = serializers.ProjectSerializer
@@ -270,7 +270,7 @@ class ProjectViewSet(LOFARViewSet):
         return queryset
 
 
-@permission_classes((DjangoModelPermissions,))
+@permission_classes((TMSSDjangoModelPermissions,))
 class ProjectNestedViewSet(LOFARNestedViewSet):
     queryset = models.Project.objects.all()
     serializer_class = serializers.ProjectSerializer
@@ -714,8 +714,8 @@ class SchedulingUnitBlueprintNestedViewSet(LOFARNestedViewSet):
 class TaskDraftViewSet(LOFARViewSet):
     queryset = models.TaskDraft.objects.all()
     serializer_class = serializers.TaskDraftSerializer
-    permission_classes = (IsProjectMember, IsAuthenticated)
-    filter_backends = (IsProjectMemberFilterBackend,)
+    permission_classes = (TMSSPermissions,) # todo: move to LOFARViewSet eventually?  # Note: this should work the same, but something funny is going on: [IsProjectMember | TMSSDjangoModelPermissions]
+    filter_backends = (IsProjectMemberFilterBackend,) # todo: move to LOFARViewSet eventually?
 
     # prefetch all reverse related references from other models on their related_name to avoid a ton of duplicate queries
     queryset = queryset.prefetch_related('first_scheduling_relation') \
@@ -755,7 +755,7 @@ class TaskDraftViewSet(LOFARViewSet):
         # todo: it seems there is no way to pass IsProjectMember as a permission class to actions without explicitly
         #  registering them in the router for some reason. but explicitly doing a check_object_permission works as well.
         #  We may want to extend get_object_or_404 to also perform a permission check before returning an object...?
-        self.check_object_permissions(self.request, task_draft)
+        self.check_object_permissions(self.request, task_draft) # or request.user.has_perm('create_task_blueprint')
         task_blueprint = create_task_blueprint_from_task_draft(task_draft)
 
         # url path magic to construct the new task_blueprint_path url
diff --git a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
index 1ba4c5d30de2d0d93c3757f133f7df8bba6e5ab2..55518e6f348f1e37fa96b12c604b41fceb55d7dc 100755
--- a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
+++ b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
@@ -2986,7 +2986,6 @@ class SystemRolePermissionTestCase(unittest.TestCase):
 
     # Cycle
 
-    @unittest.skip('Fix this test. Why can we view this without permission?')  # todo!
     def test_Cycle_cannot_be_viewed_without_scientist_group(self):
         user = User.objects.get(username='paulus')
         user.groups.set([])
@@ -3069,7 +3068,6 @@ class SystemRolePermissionTestCase(unittest.TestCase):
 
     # Project
 
-    @unittest.skip('Fix this test. Why can we view this without permission?')  # todo!
     def test_Project_cannot_be_viewed_without_scientist_group(self):
         user = User.objects.get(username='paulus')
         user.groups.set([])
diff --git a/SAS/TMSS/test/test_utils.py b/SAS/TMSS/test/test_utils.py
index 3cc7daa0cb7645e5fc7ed8c010aadf5d991e6a87..e1c0aec9040c2bd9d814469733fb13e1b2e69034 100644
--- a/SAS/TMSS/test/test_utils.py
+++ b/SAS/TMSS/test/test_utils.py
@@ -562,7 +562,7 @@ def main_test_environment():
     parser.add_option_group(group)
     group.add_option('-d', '--data', dest='data', action='store_true', help='populate the test-database with test/example data. This implies -s/--schemas because these schemas are needed to create test data.')
     group.add_option('-s', '--schemas', dest='schemas', action='store_true', help='populate the test-database with the TMSS JSON schemas')
-    group.add_option('-p', '--permissions', dest='permissions', action='store_true', help='populate the test-database with the TMSS permissions')
+    group.add_option('-M', '--permissions', dest='permissions', action='store_true', help='populate the test-database with the TMSS permissions')
     group.add_option('-m', '--eventmessages', dest='eventmessages', action='store_true', help='Send event messages over the messagebus for changes in the TMSS database (for (sub)tasks/scheduling_units etc).')
     group.add_option('-r', '--ra_test_environment', dest='ra_test_environment', action='store_true', help='start the Resource Assigner test environment which enables scheduling.')
     group.add_option('-S', '--scheduling', dest='scheduling', action='store_true', help='start the TMSS background scheduling services for dynamic scheduling of schedulingunits and subtask scheduling of chains of dependend subtasks.')