From 79baeae63fb55b1aba65f0b85442648bb1731545 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Sat, 15 Apr 2023 00:08:46 +0200
Subject: [PATCH] WIP on tests

---
 .../dbrepo-realm.json                         |  82 ++-
 .../tuwien/endpoints/ContainerEndpoint.java   |  17 +-
 .../at/tuwien/auth/AuthTokenFilterTest.java   | 101 ----
 .../ContainerEndpointIntegrationTest.java     | 243 ++------
 .../endpoint/ContainerEndpointUnitTest.java   | 550 ------------------
 .../endpoint/ImageEndpointUnitTest.java       | 192 +-----
 .../ContainerServiceIntegrationTest.java      |   2 +-
 .../rest-service/src/test/resources/view.sql  |   5 -
 .../java/at/tuwien/mapper/UserMapper.java     |  14 +-
 .../at/tuwien/endpoints/DatabaseEndpoint.java |  41 +-
 .../endpoint/AccessEndpointUnitTest.java      |  96 ++-
 .../endpoint/DatabaseEndpointUnitTest.java    | 517 +++-------------
 .../tuwien/service/AccessServiceUnitTest.java |   1 -
 .../service/DatabaseServiceComponentTest.java |  31 +-
 .../DatabaseServiceIntegrationTest.java       |  51 +-
 .../at/tuwien/mapper/ContainerMapper.java     |   2 +-
 .../java/at/tuwien/mapper/DatabaseMapper.java |   2 +-
 .../java/at/tuwien/mapper/ImageMapper.java    |   4 +
 .../repository/jpa/RealmRepository.java       |   9 +
 .../service/impl/AccessServiceImpl.java       |   4 -
 .../service/impl/MariaDbServiceImpl.java      |   1 +
 .../tuwien/entities/{auth => user}/Realm.java |   6 +-
 .../java/at/tuwien/entities/user/User.java    |  15 +-
 .../java/at/tuwien/config/RabbitMqConfig.java |   3 +-
 .../main/java/at/tuwien/test/BaseTest.java    | 107 +++-
 .../main/java/at/tuwien/utils/ArrayUtil.java  |  16 +
 dbrepo-ui/api/database.service.js             |  30 +
 dbrepo-ui/api/identifier.service.js           |  20 +-
 dbrepo-ui/api/middleware.service.js           |  17 +
 dbrepo-ui/api/query.service.js                |   4 +-
 dbrepo-ui/api/table.service.js                |  13 +
 dbrepo-ui/components/QueryList.vue            |  54 +-
 dbrepo-ui/components/TableToolbar.vue         |  57 +-
 dbrepo-ui/components/UserToolbar.vue          |  12 -
 dbrepo-ui/components/ViewList.vue             |  49 +-
 dbrepo-ui/components/query/Builder.vue        |  64 +-
 dbrepo-ui/layouts/default.vue                 |   2 +-
 37 files changed, 637 insertions(+), 1797 deletions(-)
 delete mode 100644 dbrepo-container-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
 delete mode 100644 dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
 delete mode 100644 dbrepo-container-service/rest-service/src/test/resources/view.sql
 create mode 100644 dbrepo-database-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
 rename dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/{auth => user}/Realm.java (78%)
 create mode 100644 dbrepo-metadata-db/test/src/main/java/at/tuwien/utils/ArrayUtil.java

diff --git a/dbrepo-authentication-service/dbrepo-realm.json b/dbrepo-authentication-service/dbrepo-realm.json
index afe3f517a9..0dbcd6bb72 100644
--- a/dbrepo-authentication-service/dbrepo-realm.json
+++ b/dbrepo-authentication-service/dbrepo-realm.json
@@ -61,7 +61,7 @@
       "description" : "${escalated-container-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "delete-container" ]
+        "realm" : [ "modify-foreign-container-state", "delete-container" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -187,6 +187,17 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "973f0999-cc70-4b28-9f43-979c470bea8e",
+      "name" : "default-data-steward-roles",
+      "description" : "${default-data-steward-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "e1383fb7-d54c-4732-9146-93030eb2ca50",
       "name" : "escalated-query-handling",
@@ -394,6 +405,17 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "e4bfaf36-9a5d-43e0-9fa3-0f4ea7bad8d0",
+      "name" : "default-developer-roles",
+      "description" : "${default-developer-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-query-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "feb612cc-96a6-4ed2-aaa5-01f39b25beb5",
       "name" : "insert-table-data",
@@ -434,6 +456,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "022605d2-2a40-4cfc-9864-28a56cf7d565",
+      "name" : "modify-foreign-container-state",
+      "description" : "${modify-foreign-container-state}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "2963c2bb-b129-4224-b98f-c8eeab8e72d1",
       "name" : "create-table",
@@ -870,7 +900,7 @@
   "otpPolicyLookAheadWindow" : 1,
   "otpPolicyPeriod" : 30,
   "otpPolicyCodeReusable" : false,
-  "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ],
+  "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName", "totpAppFreeOTPName" ],
   "webAuthnPolicyRpEntityName" : "keycloak",
   "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
   "webAuthnPolicyRpId" : "",
@@ -1860,7 +1890,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-user-property-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper" ]
       }
     }, {
       "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979",
@@ -1869,7 +1899,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper" ]
       }
     } ],
     "org.keycloak.keys.KeyProvider" : [ {
@@ -1921,7 +1951,7 @@
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "f687eb46-5fae-49f4-a38c-e34263c44f45",
+    "id" : "2659228d-907e-4832-9478-93c1537361ad",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -1943,7 +1973,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "f97dde75-21ae-4e8e-be0b-1e74f876a1dd",
+    "id" : "6f2ebe37-d1c9-4359-8516-05f7c435a09c",
     "alias" : "Authentication Options",
     "description" : "Authentication options.",
     "providerId" : "basic-flow",
@@ -1972,7 +2002,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "3e54a8dd-917e-424d-adb8-78e0e90fe18f",
+    "id" : "e8ecd6b9-5991-4a84-b52d-bc9961d05f9a",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1994,7 +2024,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "f22e8af1-8e3c-4399-a8e1-3a0a285e7d65",
+    "id" : "91815128-e40c-4800-946d-09d2f33a1f39",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2016,7 +2046,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6889ac8b-1fb5-4504-a480-34bdf6d6e041",
+    "id" : "90383773-dec6-4dc3-a6ff-5dfdde0ecda5",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2038,7 +2068,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "33eab85c-b74a-4e81-8624-fa068545c1f1",
+    "id" : "ae5a2e94-c9b0-4851-b88e-4b0acacb645f",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -2060,7 +2090,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ae3d35c8-14e7-4723-86df-d0898fe5bec5",
+    "id" : "a754b5ae-bc9d-4a98-ad59-6cc8ff27d016",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2082,7 +2112,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "8d60cb94-57a7-4150-979d-626358119e36",
+    "id" : "bdf46041-56db-445a-b4f3-3d000b239b8b",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2105,7 +2135,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ff6c20e7-b379-4055-99b9-7a2e4024e138",
+    "id" : "1915f7a6-19a4-4e54-8010-73c939f18afe",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2127,7 +2157,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "373b8617-2016-4df5-bf1b-75b8a67ec8b2",
+    "id" : "b3d8705b-5235-43da-89c6-ce55fb304ae5",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2163,7 +2193,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "61a55658-9750-44ce-8edf-51030643b9eb",
+    "id" : "33efb232-46c9-4482-ba8e-7e452668bafa",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2199,7 +2229,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "be7636a4-4efa-4f88-894f-fbefa8750f31",
+    "id" : "f94e82fa-882d-4952-88c9-3aa37d9be1b6",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2228,7 +2258,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "7fa9637a-ab90-42b4-95da-ed93c3480ba4",
+    "id" : "15948c95-df50-4304-8695-f586e5351979",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2243,7 +2273,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "48f53c92-8d4a-4e48-9bb1-de1daf756332",
+    "id" : "1983ebae-21b2-4a31-8517-c7a4746fedeb",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2266,7 +2296,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "34bcc343-9321-41d3-aa33-eb653181812d",
+    "id" : "f9893ead-c7a1-404b-aca2-d24e03eb5c16",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2288,7 +2318,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ff3d99ae-9bbd-46aa-9c29-0c55d3c5c9c4",
+    "id" : "d830402e-475d-46b5-a9d7-1105436d9092",
     "alias" : "http challenge",
     "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
     "providerId" : "basic-flow",
@@ -2310,7 +2340,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "103b0a30-7ad6-41ec-827f-bacdb155496f",
+    "id" : "0de6040b-5167-4ab1-8e40-f633419b5890",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2326,7 +2356,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "f080e6b0-a34e-49b6-bc17-c4777e147535",
+    "id" : "84a658d1-d9ca-4090-9a86-9d45844324e2",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2362,7 +2392,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "cb302fa5-c65a-48d9-94ea-1412ac567065",
+    "id" : "9cc594f8-9bb0-4557-bffb-4a66b2eb0f34",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2398,7 +2428,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "b281b498-55a2-4909-9138-bc9bde251925",
+    "id" : "d2b1442c-c5db-4e3f-94f6-48196fccd207",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2414,13 +2444,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "78adce28-a91c-4e60-9816-d521ac667de1",
+    "id" : "aebc30c4-79b7-47c5-8d13-f4cfe66aba10",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "1474c494-141c-448d-a5ec-45c4e43a5939",
+    "id" : "5c00357d-8701-4848-a920-0ae1db86fdd0",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
diff --git a/dbrepo-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 0706ce0fd1..0c9cf4e4a6 100644
--- a/dbrepo-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/dbrepo-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -21,6 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -166,7 +168,7 @@ public class ContainerEndpoint {
     @PutMapping("/{id}")
     @Transactional
     @Timed(value = "container.modify", description = "Time needed to modify the container state")
-    @PreAuthorize("hasAuthority('modify-container-state')")
+    @PreAuthorize("hasAuthority('modify-container-state') or hasAuthority('modify-foreign-container-state')")
     @Operation(summary = "Modify some container", security = @SecurityRequirement(name = "bearerAuth"))
     @ApiResponses(value = {
             @ApiResponse(responseCode = "200",
@@ -194,13 +196,18 @@ public class ContainerEndpoint {
                                                     @Valid @RequestBody ContainerChangeDto changeDto,
                                                     @NotNull Principal principal)
             throws ContainerNotFoundException, ContainerAlreadyRunningException, ContainerAlreadyStoppedException,
-            UserNotFoundException, NotAllowedException, DockerClientException {
+            UserNotFoundException, NotAllowedException {
         log.debug("endpoint modify container, containerId={}, changeDto={}, principal={}", containerId, changeDto, principal);
         final User user = userService.findByUsername(principal.getName());
         final Container container = containerService.find(containerId);
-        if (!(container.getCreator().getId().equals(user.getId()))) {
-            log.error("Failed to modify container because it is not owned '{}' by the current user {} or is not developer", container.getCreator().getUsername(), user.getUsername());
-            throw new NotAllowedException("Failed to modify container because it is not owned by the current user or is not developer");
+        final Authentication authentication = (Authentication) principal;
+        if (authentication.getAuthorities().stream().noneMatch(a -> a.getAuthority().equals("modify-foreign-container-state"))
+                && !(container.getOwner().getId().equals(user.getId()))) {
+            log.error("Failed to modify container: not owner and no sufficient privileges");
+            log.debug("relevant privileges found: {}", authentication.getAuthorities().stream()
+                    .filter(a -> a.getAuthority().startsWith("modify-") && a.getAuthority().endsWith("container-state"))
+                    .collect(Collectors.toList()));
+            throw new NotAllowedException("Failed to modify container: not owner and no sufficient privileges");
         }
         final Container entity;
         if (changeDto.getAction().equals(ContainerActionTypeDto.START)) {
diff --git a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
deleted file mode 100644
index b3ff7bc22a..0000000000
--- a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package at.tuwien.auth;
-
-import at.tuwien.BaseUnitTest;
-import at.tuwien.config.H2Utils;
-import at.tuwien.config.ReadyConfig;
-import at.tuwien.repository.jpa.UserRepository;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.mock.web.MockFilterChain;
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.mock.web.MockHttpServletResponse;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import java.io.IOException;
-import java.util.Optional;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.when;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class AuthTokenFilterTest extends BaseUnitTest {
-
-    @MockBean
-    private ReadyConfig readyConfig;
-
-    @MockBean
-    private UserRepository userRepository;
-
-    @Autowired
-    private AuthTokenFilter authTokenFilter;
-
-    @Autowired
-    private H2Utils h2Utils;
-
-    @BeforeEach
-    public void beforeEach() {
-        h2Utils.runScript("view.sql");
-    }
-
-    @Test
-    public void doFilterInternal_notFound_fails() throws ServletException {
-        final MockHttpServletRequest request = new MockHttpServletRequest();
-        request.addHeader("Authorization", "Bearer " + null);
-        final MockHttpServletResponse response = new MockHttpServletResponse();
-        final FilterChain chain = new MockFilterChain();
-
-        /* mock */
-        when(userRepository.findByUsername("mweise"))
-                .thenReturn(Optional.empty());
-
-        /* test */
-        assertThrows(ServletException.class, () -> {
-            authTokenFilter.doFilterInternal(request, response, chain);
-        });
-    }
-
-    @Test
-    public void doFilterInternal_succeeds() throws ServletException, IOException {
-        final MockHttpServletRequest request = new MockHttpServletRequest();
-        request.addHeader("Authorization", "Bearer " + null);
-        final MockHttpServletResponse response = new MockHttpServletResponse();
-        final FilterChain chain = new MockFilterChain();
-
-        /* mock */
-        when(userRepository.findByUsername("mweise"))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        authTokenFilter.doFilterInternal(request, response, chain);
-        assertEquals(200, response.getStatus());
-    }
-
-    @Test
-    public void parseJwt_fails() {
-        final MockHttpServletRequest request = new MockHttpServletRequest();
-        request.addHeader("Authorization", "Basic dXNlcjpwYXNz");
-
-        /* test */
-        final String response = authTokenFilter.parseJwt(request);
-        assertNull(response);
-    }
-
-    @Test
-    public void parseJwt_noAuthenticationHeader_fails() {
-        final MockHttpServletRequest request = new MockHttpServletRequest();
-
-        /* test */
-        final String response = authTokenFilter.parseJwt(request);
-        assertNull(response);
-    }
-
-}
diff --git a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointIntegrationTest.java b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointIntegrationTest.java
index 796974caf1..5f7a5733ac 100644
--- a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointIntegrationTest.java
+++ b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointIntegrationTest.java
@@ -17,7 +17,6 @@ import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
 import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -46,17 +45,9 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     @Autowired
     private ContainerEndpoint containerEndpoint;
 
-    @Test
-    public void findById_anonymous_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
     @Test
     @WithAnonymousUser
-    public void findById_anonymous2_succeeds() throws DockerClientException, ContainerNotFoundException,
+    public void findById_anonymous_succeeds() throws DockerClientException, ContainerNotFoundException,
             ContainerNotRunningException {
 
         /* test */
@@ -64,8 +55,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcher_succeeds() throws DockerClientException, ContainerNotFoundException,
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-container"})
+    public void findById_hasRole_succeeds() throws DockerClientException, ContainerNotFoundException,
             ContainerNotRunningException {
 
         /* mock */
@@ -77,21 +68,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findById_developer_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findById_dataSteward_succeeds() throws DockerClientException, ContainerNotFoundException,
+    @WithMockUser(username = USER_3_USERNAME)
+    public void findById_noRole_succeeds() throws DockerClientException, ContainerNotFoundException,
             ContainerNotRunningException {
 
         /* mock */
@@ -102,18 +80,9 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
         findById_generic(CONTAINER_1_ID, CONTAINER_1);
     }
 
-    @Test
-    public void delete_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void delete_anonymous2_fails() {
+    public void delete_anonymous_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -122,22 +91,22 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void delete_researcher_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void delete_noRole_fails() {
 
         /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
+        when(userRepository.findByUsername(USER_3_USERNAME))
+                .thenReturn(Optional.of(USER_3));
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
+            delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_3_PRINCIPAL);
         });
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void delete_developer_succeeds() throws ContainerStillRunningException, ContainerAlreadyRemovedException,
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-container"})
+    public void delete_hasRole_succeeds() throws ContainerStillRunningException, ContainerAlreadyRemovedException,
             ContainerNotFoundException, DockerClientException {
 
         /* mock */
@@ -148,38 +117,17 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
         delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_2_PRINCIPAL);
     }
 
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void delete_dataSteward_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void findAll_anonymous_succeeds() {
-
-        /* test */
-        findAll_generic(null, null);
-    }
-
     @Test
     @WithAnonymousUser
-    public void findAll_anonymous2_succeeds() {
+    public void findAll_anonymous_succeeds() {
 
         /* test */
         findAll_generic(null, null);
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findAll_researcher_succeeds() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-containers"})
+    public void findAll_hasRole_succeeds() {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -190,20 +138,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findAll_developer_succeeds() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        findAll_generic(USER_2_PRINCIPAL, null);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findAll_dataSteward_succeeds() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void findAll_noRole_succeeds() {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
@@ -213,23 +149,9 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
         findAll_generic(USER_3_PRINCIPAL, null);
     }
 
-    @Test
-    public void create_anonymous_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            create_generic(request, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void create_anonymous2_fails() {
+    public void create_anonymous_fails() {
         final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
                 .name(CONTAINER_1_NAME)
                 .repository(IMAGE_1_REPOSITORY)
@@ -243,8 +165,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcher_succeeds() throws UserNotFoundException, DockerClientException,
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"create-container"})
+    public void create_hasRole_succeeds() throws UserNotFoundException, DockerClientException,
             ContainerAlreadyExistsException, ImageNotFoundException {
         final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
                 .name(CONTAINER_1_NAME)
@@ -261,40 +183,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcherEmpty_fails() throws UserNotFoundException, DockerClientException,
-            ContainerAlreadyExistsException, ImageNotFoundException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        create_generic(null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void create_developer_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            create_generic(request, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void create_dataSteward_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void create_noRole_fails() {
         final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
                 .name(CONTAINER_1_NAME)
                 .repository(IMAGE_1_REPOSITORY)
@@ -311,18 +201,9 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
         });
     }
 
-    @Test
-    public void modify_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void modify_anonymous2_fails() {
+    public void modify_anonymous_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -331,8 +212,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStart_succeeds() throws ContainerAlreadyRunningException,
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-container-state"})
+    public void modify_hasRole_succeeds() throws ContainerAlreadyRunningException,
             ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
             DockerClientException {
 
@@ -345,57 +226,22 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStart_fails() throws ContainerNotFoundException, ContainerAlreadyRunningException {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void modify_noRole_fails() {
 
         /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-        doThrow(ContainerAlreadyRunningException.class)
-                .when(containerService)
-                .start(CONTAINER_1_ID);
-
-        /* test */
-        assertThrows(ContainerAlreadyRunningException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStop_succeeds() throws ContainerAlreadyRunningException,
-            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
-            DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStop_fails() throws ContainerAlreadyStoppedException, ContainerNotFoundException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-        doThrow(ContainerAlreadyStoppedException.class)
-                .when(containerService)
-                .stop(CONTAINER_1_ID);
-
+        when(userRepository.findByUsername(USER_3_USERNAME))
+                .thenReturn(Optional.of(USER_3));
 
         /* test */
-        assertThrows(ContainerAlreadyStoppedException.class, () -> {
-            modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
+        assertThrows(AccessDeniedException.class, () -> {
+            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, USER_3_PRINCIPAL);
         });
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void modify_developerForeignStart_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-foreign-container-state"})
+    public void modify_hasRoleForeign_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
             NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
 
         /* mock */
@@ -407,21 +253,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void modify_developerForeignStop_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
-            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherForeignStart_fails() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-container-state"})
+    public void modify_notRoleForeign_fails() {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -434,8 +267,8 @@ public class ContainerEndpointIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void modify_dataStewardForeignStop_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void modify_noRoleForeign_fails() {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
diff --git a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
deleted file mode 100644
index 034f0b3272..0000000000
--- a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java
+++ /dev/null
@@ -1,550 +0,0 @@
-package at.tuwien.endpoint;
-
-import at.tuwien.BaseUnitTest;
-import at.tuwien.api.container.*;
-import at.tuwien.config.DockerDaemonConfig;
-import at.tuwien.config.ReadyConfig;
-import at.tuwien.endpoints.ContainerEndpoint;
-import at.tuwien.entities.container.Container;
-import at.tuwien.exception.*;
-import at.tuwien.repository.jpa.UserRepository;
-import at.tuwien.service.impl.ContainerServiceImpl;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
-import org.springframework.security.test.context.support.WithAnonymousUser;
-import org.springframework.security.test.context.support.WithMockUser;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import java.security.Principal;
-import java.util.List;
-import java.util.Optional;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-@Log4j2
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
-public class ContainerEndpointUnitTest extends BaseUnitTest {
-
-    @MockBean
-    private ReadyConfig readyConfig;
-
-    @MockBean
-    private ContainerServiceImpl containerService;
-
-    @MockBean
-    private UserRepository userRepository;
-
-    @Autowired
-    private ContainerEndpoint containerEndpoint;
-
-    @Autowired
-    private DockerDaemonConfig dockerUtil;
-
-    @Test
-    public void findById_anonymous_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void findById_anonymous2_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcher_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findById_developer_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findById_dataSteward_succeeds() throws DockerClientException, ContainerNotFoundException,
-            ContainerNotRunningException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1);
-    }
-
-    @Test
-    public void delete_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void delete_anonymous2_fails() {
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void delete_researcher_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void delete_developer_succeeds() throws ContainerStillRunningException, ContainerAlreadyRemovedException,
-            ContainerNotFoundException, DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void delete_dataSteward_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void findAll_anonymous_succeeds() {
-
-        /* test */
-        findAll_generic(null, null);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void findAll_anonymous2_succeeds() {
-
-        /* test */
-        findAll_generic(null, null);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findAll_researcher_succeeds() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        findAll_generic(USER_1_PRINCIPAL, null);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findAll_developer_succeeds() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        findAll_generic(USER_2_PRINCIPAL, null);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findAll_dataSteward_succeeds() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        findAll_generic(USER_3_PRINCIPAL, null);
-    }
-
-    @Test
-    public void create_anonymous_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            create_generic(request, null);
-        });
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void create_anonymous2_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            create_generic(request, null);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcher_succeeds() throws UserNotFoundException, DockerClientException,
-            ContainerAlreadyExistsException, ImageNotFoundException {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        create_generic(request, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcherEmpty_fails() throws UserNotFoundException, DockerClientException,
-            ContainerAlreadyExistsException, ImageNotFoundException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        create_generic(null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void create_developer_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            create_generic(request, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void create_dataSteward_fails() {
-        final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
-                .name(CONTAINER_1_NAME)
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            create_generic(request, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void modify_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void modify_anonymous2_fails() {
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, null);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStart_succeeds() throws ContainerAlreadyRunningException,
-            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
-            DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStart_fails() throws ContainerNotFoundException, ContainerAlreadyRunningException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-        doThrow(ContainerAlreadyRunningException.class)
-                .when(containerService)
-                .start(CONTAINER_1_ID);
-
-        /* test */
-        assertThrows(ContainerAlreadyRunningException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStop_succeeds() throws ContainerAlreadyRunningException,
-            ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException,
-            DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherStop_fails() throws ContainerAlreadyStoppedException, ContainerNotFoundException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-        doThrow(ContainerAlreadyStoppedException.class)
-                .when(containerService)
-                .stop(CONTAINER_1_ID);
-
-
-        /* test */
-        assertThrows(ContainerAlreadyStoppedException.class, () -> {
-            modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void modify_developerForeignStart_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
-            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.START, CONTAINER_1_ID, CONTAINER_1, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void modify_developerForeignStop_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException,
-            NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcherForeignStart_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            modify_generic(ContainerActionTypeDto.START, CONTAINER_2_ID, CONTAINER_2, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void modify_dataStewardForeignStop_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            modify_generic(ContainerActionTypeDto.STOP, CONTAINER_1_ID, CONTAINER_1, USER_3_PRINCIPAL);
-        });
-    }
-
-    /* ################################################################################################### */
-    /* ## GENERIC TEST CASES                                                                            ## */
-    /* ################################################################################################### */
-
-    public void findById_generic(Long containerId, Container container) throws DockerClientException,
-            ContainerNotFoundException, ContainerNotRunningException {
-
-        /* mock */
-        when(containerService.find(containerId))
-                .thenReturn(container);
-        when(containerService.inspect(containerId))
-                .thenReturn(container);
-
-        /* test */
-        final ResponseEntity<ContainerDto> response = containerEndpoint.findById(containerId);
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertNotNull(response.getBody());
-        final ContainerDto dto = response.getBody();
-        assertEquals(ContainerStateDto.RUNNING, dto.getState());
-    }
-
-    public void delete_generic(Long containerId, Container container, Principal principal) throws ContainerNotFoundException,
-            ContainerStillRunningException, ContainerAlreadyRemovedException, DockerClientException {
-
-        /* mock */
-        when(containerService.find(containerId))
-                .thenReturn(container);
-        doNothing()
-                .when(containerService)
-                .remove(CONTAINER_1_ID);
-
-        /* test */
-        final ResponseEntity<?> response = containerEndpoint.delete(containerId, principal);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNull(response.getBody());
-    }
-
-    public void findAll_generic(Principal principal, Integer limit) {
-
-        /* mock */
-        when(containerService.getAll(limit))
-                .thenReturn(List.of(CONTAINER_1, CONTAINER_2));
-
-        /* test */
-        final ResponseEntity<List<ContainerBriefDto>> response = containerEndpoint.findAll(principal, limit);
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertNotNull(response.getBody());
-        final List<ContainerBriefDto> body = response.getBody();
-        assertEquals(2, body.size());
-        final ContainerBriefDto container1 = body.get(0);
-        assertEquals(CONTAINER_1_ID, container1.getId());
-        assertEquals(CONTAINER_1_NAME, container1.getName());
-        assertEquals(CONTAINER_1_INTERNALNAME, container1.getInternalName());
-        final ContainerBriefDto container2 = body.get(1);
-        assertEquals(CONTAINER_2_ID, container2.getId());
-        assertEquals(CONTAINER_2_NAME, container2.getName());
-        assertEquals(CONTAINER_2_INTERNALNAME, container2.getInternalName());
-    }
-
-    public void create_generic(ContainerCreateRequestDto data, Principal principal) throws UserNotFoundException,
-            DockerClientException, ContainerAlreadyExistsException, ImageNotFoundException {
-
-        /* mock */
-        when(containerService.create(data, principal))
-                .thenReturn(CONTAINER_1);
-
-        /* test */
-        final ResponseEntity<ContainerBriefDto> response = containerEndpoint.create(data, principal);
-        assertEquals(HttpStatus.CREATED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-    public void modify_generic(ContainerActionTypeDto data, Long containerId, Container container, Principal principal)
-            throws ContainerAlreadyRunningException, ContainerNotFoundException, ContainerAlreadyStoppedException,
-            UserNotFoundException, NotAllowedException, DockerClientException {
-        final ContainerChangeDto request = ContainerChangeDto.builder()
-                .action(data)
-                .build();
-
-        /* mock */
-        when(containerService.find(containerId))
-                .thenReturn(container);
-        if (data.equals(ContainerActionTypeDto.START)) {
-            when(containerService.start(containerId))
-                    .thenReturn(container);
-        } else if (data.equals(ContainerActionTypeDto.STOP)) {
-            when(containerService.stop(containerId))
-                    .thenReturn(container);
-        }
-
-        /* test */
-        final ResponseEntity<ContainerBriefDto> response = containerEndpoint.modify(containerId, request, principal);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-}
diff --git a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
index 196beba921..0da3f83ae6 100644
--- a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
+++ b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java
@@ -54,24 +54,17 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     @Autowired
     private DockerDaemonConfig dockerUtil;
 
-    @Test
-    public void findAll_anonymous_succeeds() {
-
-        /* test */
-        findAll_generic(null);
-    }
-
     @Test
     @WithAnonymousUser
-    public void findAll_anonymous2_succeeds() {
+    public void findAll_anonymous_succeeds() {
 
         /* test */
         findAll_generic(null);
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findAll_researcher_succeeds() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-image"})
+    public void findAll_hasRole_succeeds() {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -82,20 +75,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findAll_developer_succeeds() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        findAll_generic(USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findAll_dataSteward_succeeds() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void findAll_noRole_succeeds() {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
@@ -105,26 +86,9 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
         findAll_generic(USER_3_PRINCIPAL);
     }
 
-    @Test
-    public void create_anonymous_fails() {
-        final ImageCreateDto request = ImageCreateDto.builder()
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .defaultPort(IMAGE_1_PORT)
-                .dialect(IMAGE_1_DIALECT)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .environment(IMAGE_1_ENV_DTO)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            create_generic(request, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void create_anonymous2_fails() {
+    public void create_anonymous_fails() {
         final ImageCreateDto request = ImageCreateDto.builder()
                 .repository(IMAGE_1_REPOSITORY)
                 .tag(IMAGE_1_TAG)
@@ -141,8 +105,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcher_fails() {
+    @WithMockUser(username = USER_1_USERNAME, roles = {"create-image"})
+    public void create_hasRole_fails() {
         final ImageCreateDto request = ImageCreateDto.builder()
                 .repository(IMAGE_1_REPOSITORY)
                 .tag(IMAGE_1_TAG)
@@ -163,9 +127,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void create_developer_succeeds() throws UserNotFoundException, ImageAlreadyExistsException,
-            DockerClientException, ImageNotFoundException, ImageInvalidException {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void create_noRole_fails() {
         final ImageCreateDto request = ImageCreateDto.builder()
                 .repository(IMAGE_1_REPOSITORY)
                 .tag(IMAGE_1_TAG)
@@ -176,16 +139,18 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
                 .build();
 
         /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
+        when(userRepository.findByUsername(USER_3_USERNAME))
+                .thenReturn(Optional.of(USER_3));
 
         /* test */
-        create_generic(request, USER_2_PRINCIPAL);
+        assertThrows(AccessDeniedException.class, () -> {
+            create_generic(request, USER_3_PRINCIPAL);
+        });
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void create_developerMissingEssentialInfo_fails() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"create-image"})
+    public void create_missingEssentialInfo_fails() {
         final ImageCreateDto request = ImageCreateDto.builder()
                 .repository(IMAGE_1_REPOSITORY)
                 .tag(IMAGE_1_TAG)
@@ -196,33 +161,11 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
                 .build();
 
         /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
+        when(userRepository.findByUsername(USER_1_USERNAME))
+                .thenReturn(Optional.of(USER_1));
 
         /* test */
         assertThrows(ImageInvalidException.class, () -> {
-            create_generic(request, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void create_dataSteward_fails() {
-        final ImageCreateDto request = ImageCreateDto.builder()
-                .repository(IMAGE_1_REPOSITORY)
-                .tag(IMAGE_1_TAG)
-                .defaultPort(IMAGE_1_PORT)
-                .dialect(IMAGE_1_DIALECT)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .environment(IMAGE_1_ENV_DTO)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
             create_generic(request, USER_1_PRINCIPAL);
         });
     }
@@ -247,18 +190,9 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
         });
     }
 
-    @Test
-    public void delete_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            delete_generic(IMAGE_1_ID, IMAGE_1, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void delete_anonymous2_fails() {
+    public void delete_anonymous_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -267,8 +201,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void delete_researcher_fails() {
+    @WithMockUser(username = USER_1_USERNAME)
+    public void delete_noRole_fails() {
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
@@ -281,8 +215,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void delete_developer_succeeds() throws ImageNotFoundException {
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-image"})
+    public void delete_hasRole_succeeds() throws ImageNotFoundException {
 
         /* mock */
         when(userRepository.findByUsername(USER_2_USERNAME))
@@ -292,56 +226,9 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
         delete_generic(IMAGE_1_ID, IMAGE_1, USER_2_PRINCIPAL);
     }
 
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void delete_developer_fails() {
-
-        /* mock */
-        doThrow(DataIntegrityViolationException.class)
-                .when(imageRepository)
-                .deleteById(IMAGE_1_ID);
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        assertThrows(ImageNotFoundException.class, () -> {
-            delete_generic(IMAGE_1_ID, IMAGE_1, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void delete_dataSteward_fails() {
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            delete_generic(IMAGE_1_ID, IMAGE_1, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void modify_anonymous_fails() {
-        final ImageChangeDto request = ImageChangeDto.builder()
-                .defaultPort(IMAGE_1_PORT)
-                .dialect(IMAGE_1_DIALECT)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .driverClass(IMAGE_1_DRIVER)
-                .environment(IMAGE_1_ENV_DTO)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            modify_generic(IMAGE_1_ID, IMAGE_1, request, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void modify_anonymous2_fails() {
+    public void modify_anonymous_fails() {
         final ImageChangeDto request = ImageChangeDto.builder()
                 .defaultPort(IMAGE_1_PORT)
                 .dialect(IMAGE_1_DIALECT)
@@ -357,8 +244,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void modify_researcher_fails() {
+    @WithMockUser(username = USER_1_USERNAME)
+    public void modify_noRole_fails() {
         final ImageChangeDto request = ImageChangeDto.builder()
                 .defaultPort(IMAGE_1_PORT)
                 .dialect(IMAGE_1_DIALECT)
@@ -378,8 +265,8 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void modify_developer_succeeds() throws ImageNotFoundException {
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-image"})
+    public void modify_hasRole_succeeds() throws ImageNotFoundException {
         final ImageChangeDto request = ImageChangeDto.builder()
                 .defaultPort(IMAGE_1_PORT)
                 .dialect(IMAGE_1_DIALECT)
@@ -396,27 +283,6 @@ public class ImageEndpointUnitTest extends BaseUnitTest {
         modify_generic(IMAGE_1_ID, IMAGE_1, request, USER_2_PRINCIPAL);
     }
 
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void modify_dataSteward_fails() {
-        final ImageChangeDto request = ImageChangeDto.builder()
-                .defaultPort(IMAGE_1_PORT)
-                .dialect(IMAGE_1_DIALECT)
-                .jdbcMethod(IMAGE_1_JDBC)
-                .driverClass(IMAGE_1_DRIVER)
-                .environment(IMAGE_1_ENV_DTO)
-                .build();
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        assertThrows(AccessDeniedException.class, () -> {
-            modify_generic(IMAGE_1_ID, IMAGE_1, request, USER_3_PRINCIPAL);
-        });
-    }
-
     /* ################################################################################################### */
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
diff --git a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
index a1b1a93cd7..9345dacfc2 100644
--- a/dbrepo-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
+++ b/dbrepo-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
@@ -3,7 +3,6 @@ package at.tuwien.service;
 import at.tuwien.BaseUnitTest;
 import at.tuwien.api.container.ContainerCreateRequestDto;
 import at.tuwien.config.DockerConfig;
-import at.tuwien.config.DockerDaemonConfig;
 import at.tuwien.config.ReadyConfig;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.container.image.ContainerImage;
@@ -61,6 +60,7 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
         /* create networks */
         DockerConfig.createAllNetworks();
         /* mock data */
+        USER_1.setAttributes(List.of());
         userRepository.save(USER_1);
         imageRepository.save(ContainerImage.builder()
                 .id(IMAGE_1_ID)
diff --git a/dbrepo-container-service/rest-service/src/test/resources/view.sql b/dbrepo-container-service/rest-service/src/test/resources/view.sql
deleted file mode 100644
index b23c5436c0..0000000000
--- a/dbrepo-container-service/rest-service/src/test/resources/view.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- Modified for H2
--- Assume id=1 is invalid
--- Assume id=2 is still valid token
-CREATE VIEW IF NOT EXISTS fda.mdb_invalid_tokens AS
-(SELECT `id`, `token_hash`, `creator`, `created`, `expires`, `last_used` FROM fda.`mdb_tokens` WHERE `id` = 1);
\ No newline at end of file
diff --git a/dbrepo-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/dbrepo-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
index d92e24f645..5e47ebae63 100644
--- a/dbrepo-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
+++ b/dbrepo-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -14,6 +14,7 @@ import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
 import java.util.Arrays;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 @Mapper(componentModel = "spring")
@@ -23,16 +24,25 @@ public interface UserMapper {
 
     /* keep */
     @Mappings({
-            @Mapping(target = "orcid", expression = "java(data.getAttributes().stream().filter(a -> a.getName().equals(\"orcid\")).findFirst().get().getValue())")
+            @Mapping(target = "orcid", expression = "java(userToOrcid(data))")
     })
     UserBriefDto userToUserBriefDto(User data);
 
     /* keep */
     @Mappings({
-            @Mapping(target = "orcid", expression = "java(data.getAttributes().stream().filter(a -> a.getName().equals(\"orcid\")).findFirst().get().getValue())")
+            @Mapping(target = "orcid", expression = "java(userToOrcid(data))")
     })
     UserDto userToUserDto(User data);
 
+    /* keep */
+    default String userToOrcid(User data) {
+        if (data.getAttributes() == null) {
+            return null;
+        }
+        final Optional<UserAttribute> orcid = data.getAttributes().stream().filter(a -> a.getName().equals("orcid")).findFirst();
+        return orcid.map(UserAttribute::getValue).orElse(null);
+    }
+
     UserDetailsDto userBriefDtoToUserDetailsDto(UserBriefDto data);
 
     default UserDetailsDto tokenIntrospectDtoToUserDetailsDto(TokenIntrospectDto data) {
diff --git a/dbrepo-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index 49bfda53cb..b2c23b9183 100644
--- a/dbrepo-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -2,6 +2,7 @@ package at.tuwien.endpoints;
 
 import at.tuwien.api.database.*;
 import at.tuwien.api.error.ApiErrorDto;
+import at.tuwien.entities.container.Container;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.entities.user.User;
@@ -40,16 +41,19 @@ public class DatabaseEndpoint {
     private final UserService userService;
     private final AccessService accessService;
     private final DatabaseMapper databaseMapper;
+    private final ContainerService containerService;
     private final MariaDbServiceImpl databaseService;
     private final QueryStoreService queryStoreService;
     private final MessageQueueService messageQueueService;
     private final DatabaseAccessRepository databaseAccessRepository;
 
     @Autowired
-    public DatabaseEndpoint(DatabaseMapper databaseMapper, UserService userService, MariaDbServiceImpl databaseService,
-                            QueryStoreService queryStoreService, MessageQueueService messageQueueService,
-                            AccessService accessService, DatabaseAccessRepository databaseAccessRepository) {
+    public DatabaseEndpoint(DatabaseMapper databaseMapper, UserService userService, ContainerService containerService,
+                            MariaDbServiceImpl databaseService, QueryStoreService queryStoreService,
+                            MessageQueueService messageQueueService, AccessService accessService,
+                            DatabaseAccessRepository databaseAccessRepository) {
         this.userService = userService;
+        this.containerService = containerService;
         this.accessService = accessService;
         this.databaseMapper = databaseMapper;
         this.databaseService = databaseService;
@@ -142,8 +146,13 @@ public class DatabaseEndpoint {
             BrokerVirtualHostGrantException {
         log.debug("endpoint create database, containerId={}, createDto={}, principal={}", containerId, createDto,
                 principal);
-        final Database database = databaseService.create(containerId, createDto, principal);
+        final Container container = containerService.find(containerId);
         final User user = userService.findByUsername(principal.getName());
+        if (!container.getOwner().getId().equals(user.getId())) {
+            log.error("Failed to create database: not owner");
+            throw new NotAllowedException(("Failed to create database: not owner"));
+        }
+        final Database database = databaseService.create(containerId, createDto, principal);
         messageQueueService.createUser(user);
         messageQueueService.createExchange(database, principal);
         messageQueueService.updatePermissions(principal);
@@ -167,7 +176,7 @@ public class DatabaseEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = DatabaseDto.class))}),
             @ApiResponse(responseCode = "404",
-                    description = "Database could not be found",
+                    description = "Database or user could not be found",
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
@@ -181,11 +190,16 @@ public class DatabaseEndpoint {
                                                   @NotNull @PathVariable Long databaseId,
                                                   @Valid @RequestBody DatabaseModifyVisibilityDto data,
                                                   @NotNull Principal principal)
-            throws DatabaseNotFoundException {
+            throws DatabaseNotFoundException, UserNotFoundException, NotAllowedException {
         log.debug("endpoint update database, containerId={}, databaseId={}, data={}, principal={}", containerId,
                 databaseId, data, principal);
-        final Database database = databaseService.visibility(containerId, databaseId, data);
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
+        final Database database = databaseService.findById(containerId, databaseId);
+        final User user = userService.findByUsername(principal.getName());
+        if (!database.getOwner().getId().equals(user.getId())) {
+            log.error("Failed to create database: not owner");
+            throw new NotAllowedException(("Failed to create database: not owner"));
+        }
+        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.visibility(containerId, databaseId, data));
         log.trace("update database resulted in database {}", dto);
         return ResponseEntity.accepted()
                 .body(dto);
@@ -217,11 +231,16 @@ public class DatabaseEndpoint {
                                                 @NotNull @PathVariable Long databaseId,
                                                 @Valid @RequestBody DatabaseTransferDto transferDto,
                                                 @NotNull Principal principal)
-            throws DatabaseNotFoundException, UserNotFoundException {
+            throws DatabaseNotFoundException, UserNotFoundException, NotAllowedException {
         log.debug("endpoint update database, containerId={}, databaseId={}, transferDto={}, principal={}", containerId,
                 databaseId, transferDto, principal);
-        final Database database = databaseService.transfer(containerId, databaseId, transferDto);
-        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
+        final Database database = databaseService.findById(containerId, databaseId);
+        final User user = userService.findByUsername(principal.getName());
+        if (!database.getOwner().getId().equals(user.getId())) {
+            log.error("Failed to create database: not owner");
+            throw new NotAllowedException(("Failed to create database: not owner"));
+        }
+        final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.transfer(containerId, databaseId, transferDto));
         log.trace("update database resulted in database {}", dto);
         return ResponseEntity.accepted()
                 .body(dto);
diff --git a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
index 4f7ff26b1a..e8e9192e1c 100644
--- a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
+++ b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java
@@ -24,6 +24,8 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.test.context.support.WithAnonymousUser;
+import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.security.Principal;
@@ -62,69 +64,48 @@ public class AccessEndpointUnitTest extends BaseUnitTest {
     private AccessMapper accessMapper;
 
     @Test
+    @WithAnonymousUser
     public void create_anonymous_fails() {
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
             generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_2_USERNAME, USER_2, null);
         });
     }
 
     @Test
-    @Disabled("Requires integration")
-    public void create_privateResearcherNoAccessOwner_succeeds() throws UserNotFoundException, NotAllowedException,
+    @Disabled("not unit test")
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-access"})
+    public void create_hasRoleNoAccess_succeeds() throws UserNotFoundException, NotAllowedException,
             QueryMalformedException, DatabaseNotFoundException, DatabaseMalformedException {
 
         /* test */
-        generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_2_USERNAME, USER_2, USER_1_PRINCIPAL);
+        generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_1_USERNAME, USER_1, USER_1_PRINCIPAL);
     }
 
     @Test
-    public void create_privateResearcherNoAccess_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void create_noRoleNoAccess_fails() {
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_3_USERNAME, USER_3, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void create_privateResearcherRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_READ_ACCESS, USER_2_USERNAME, USER_2, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void create_privateResearcherWriteOwn_fails() {
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS, USER_2_USERNAME, USER_2, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void create_privateResearcherWriteAll_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_ALL_ACCESS, USER_2_USERNAME, USER_2, USER_1_PRINCIPAL);
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            generic_create(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_3_USERNAME, USER_3, USER_3_PRINCIPAL);
         });
     }
 
     @Test
+    @WithAnonymousUser
     public void find_anonymous_fails() {
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_find(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_2_USERNAME, USER_2_ID, null);
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            generic_find(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_1_USERNAME, null, null);
         });
     }
 
     @Test
-    public void find_noAccess_fails() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"check-database-access"})
+    public void find_hasRoleNoAccess_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -133,27 +114,15 @@ public class AccessEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    public void find_privateResearcherRead_succeeds() throws AccessDeniedException, NotAllowedException {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"check-database-access"})
+    public void find_hasRoleHasAccess_fails() throws AccessDeniedException, NotAllowedException {
 
         /* test */
         generic_find(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_READ_ACCESS, USER_2_USERNAME, USER_2_ID, USER_1_PRINCIPAL);
     }
 
     @Test
-    public void find_privateResearcherWriteOwn_succeeds() throws AccessDeniedException, NotAllowedException {
-
-        /* test */
-        generic_find(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS, USER_2_USERNAME, USER_2_ID, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void find_privateResearcherWriteAll_succeeds() throws AccessDeniedException, NotAllowedException {
-
-        /* test */
-        generic_find(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_ALL_ACCESS, USER_2_USERNAME, USER_2_ID, USER_1_PRINCIPAL);
-    }
-
-    @Test
+    @WithAnonymousUser
     public void update_anonymous_fails() {
 
         /* mock */
@@ -161,47 +130,50 @@ public class AccessEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
             generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_3_USERNAME, null);
         });
     }
 
     @Test
-    public void update_privateResearcherRead_fails() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_hasRoleNoAccess_fails() {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_READ_ACCESS, USER_3_USERNAME, USER_1_PRINCIPAL);
+        assertThrows(AccessDeniedException.class, () -> {
+            generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_3_USERNAME, USER_1_PRINCIPAL);
         });
     }
 
     @Test
-    public void update_privateResearcherWriteOwn_fails() {
+    @Disabled("not unit test")
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_hasRoleHasAccess_succeeds() throws UserNotFoundException, AccessDeniedException,
+            NotAllowedException, QueryMalformedException, DatabaseNotFoundException, DatabaseMalformedException {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS, USER_3_USERNAME, USER_1_PRINCIPAL);
-        });
+        generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_DATA_STEWARD_READ_ACCESS, USER_3_USERNAME, USER_1_PRINCIPAL);
     }
 
     @Test
-    public void update_privateResearcherWriteAll_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void update_noRoleNoAccess_fails() {
 
         /* mock */
         when(userRepository.findByUsername(USER_3_USERNAME))
                 .thenReturn(Optional.of(USER_3));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, DATABASE_1_RESEARCHER_WRITE_ALL_ACCESS, USER_3_USERNAME, USER_1_PRINCIPAL);
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            generic_update(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, null, USER_3_USERNAME, USER_3_PRINCIPAL);
         });
     }
 
diff --git a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
index 674cfe0f16..cc40ad18b0 100644
--- a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
+++ b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java
@@ -15,6 +15,7 @@ import at.tuwien.service.MessageQueueService;
 import at.tuwien.service.QueryStoreService;
 import at.tuwien.test.BaseTest;
 import com.rabbitmq.client.Channel;
+import lombok.With;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.*;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -78,22 +79,16 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     @Autowired
     private DatabaseEndpoint databaseEndpoint;
 
-    @Test
-    public void create_anonymous_fails() {
-        final DatabaseCreateDto request = DatabaseCreateDto.builder()
-                .name(DATABASE_1_NAME)
-                .isPublic(DATABASE_1_PUBLIC)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            create_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, null, request, null);
-        });
+    @BeforeEach
+    public void beforeEach() {
+        DATABASE_1.setOwner(DATABASE_1_OWNER);
+        DATABASE_2.setOwner(DATABASE_2_OWNER);
+        DATABASE_3.setOwner(DATABASE_3_OWNER);
     }
 
     @Test
     @WithAnonymousUser
-    public void create_anonymous2_fails() {
+    public void create_anonymous_fails() {
         final DatabaseCreateDto request = DatabaseCreateDto.builder()
                 .name(DATABASE_1_NAME)
                 .isPublic(DATABASE_1_PUBLIC)
@@ -106,8 +101,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void create_dataSteward_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void create_noRole_fails() {
         final DatabaseCreateDto request = DatabaseCreateDto.builder()
                 .name(DATABASE_3_NAME)
                 .isPublic(DATABASE_3_PUBLIC)
@@ -124,46 +119,26 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_4_USERNAME, roles = {"RESEARCHER"})
-    public void create_researcherForeign_fails() {
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"create-database"})
+    public void create_hasRoleForeign_fails() {
         final DatabaseCreateDto request = DatabaseCreateDto.builder()
                 .name(DATABASE_1_NAME)
                 .isPublic(DATABASE_1_PUBLIC)
                 .build();
 
         /* mock */
-        when(userRepository.findByUsername(USER_4_USERNAME))
-                .thenReturn(Optional.of(USER_4));
+        when(userRepository.findByUsername(USER_2_USERNAME))
+                .thenReturn(Optional.of(USER_2));
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            create_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, null, request, USER_4_PRINCIPAL);
+            create_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, null, request, USER_2_PRINCIPAL);
         });
     }
 
-    @Test
-    public void list_anonymousPublic_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), null);
-    }
-
     @Test
     @WithAnonymousUser
-    public void list_anonymous2Public_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), null);
-    }
-
-    @Test
-    public void list_anonymousPrivate_succeeds() {
+    public void list_anonymous_succeeds() {
 
         /* pre-condition */
         assertFalse(DATABASE_1_PUBLIC);
@@ -173,19 +148,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void list_anonymous2Private_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_1_PUBLIC);
-
-        /* test */
-        list_generic(CONTAINER_1_ID, DATABASE_1_ID, CONTAINER_1, List.of(DATABASE_1), null);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void list_researcherPublic_succeeds() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"list-databases"})
+    public void list_hasRole_succeeds() {
 
         /* pre-condition */
         assertTrue(DATABASE_3_PUBLIC);
@@ -199,8 +163,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void list_researcherPublicWithIdentifiers_succeeds() {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"list-databases"})
+    public void list_hasRoleForeign_succeeds() {
 
         /* pre-condition */
         assertTrue(DATABASE_3_PUBLIC);
@@ -208,217 +172,72 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
-        when(identifierRepository.findByDatabaseId(DATABASE_1_ID))
-                .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
         list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL);
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void list_researcherPrivate_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
-
-        /* test */
-        list_generic(CONTAINER_2_ID, DATABASE_2_ID, CONTAINER_2, List.of(DATABASE_2), USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void list_researcherPublicForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_1_USERNAME))
-                .thenReturn(Optional.of(USER_1));
+    @WithAnonymousUser
+    public void visibility_anonymous_fails() {
+        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
+                .isPublic(true)
+                .build();
 
         /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL);
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, null);
+        });
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void list_researcherPrivateForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-visibility"})
+    public void visibility_hasRole_succeeds() throws NotAllowedException, DatabaseNotFoundException, UserNotFoundException {
+        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
+                .isPublic(true)
+                .build();
 
         /* mock */
         when(userRepository.findByUsername(USER_1_USERNAME))
                 .thenReturn(Optional.of(USER_1));
 
         /* test */
-        list_generic(CONTAINER_2_ID, DATABASE_2_ID, CONTAINER_2, List.of(DATABASE_2), USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void list_developerPublic_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void list_developerPrivate_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        list_generic(CONTAINER_2_ID, DATABASE_2_ID, CONTAINER_2, List.of(DATABASE_2), USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void list_developerPublicForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void list_developerPrivateForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_1_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_2_USERNAME))
-                .thenReturn(Optional.of(USER_2));
-
-        /* test */
-        list_generic(CONTAINER_1_ID, DATABASE_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void list_dataStewardPublic_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void list_dataStewardPrivate_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_1_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        list_generic(CONTAINER_1_ID, DATABASE_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_3_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void list_dataStewardPublicForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        list_generic(CONTAINER_3_ID, DATABASE_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void list_dataStewardPrivateForeignContainer_succeeds() {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* mock */
-        when(userRepository.findByUsername(USER_3_USERNAME))
-                .thenReturn(Optional.of(USER_3));
-
-        /* test */
-        list_generic(CONTAINER_2_ID, DATABASE_2_ID, CONTAINER_2, List.of(DATABASE_2), USER_3_PRINCIPAL);
-    }
-
-    @Test
-    public void visibility_anonymous_fails() {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
-                .build();
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, null);
-        });
+        visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_1_PRINCIPAL);
     }
 
     @Test
-    @WithAnonymousUser
-    public void visibility_anonymous2_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void visibility_noRole_fails() {
         final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
                 .isPublic(true)
                 .build();
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, null);
+            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_3_PRINCIPAL);
         });
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void visibility_researcher_succeeds() throws NotAllowedException, DatabaseNotFoundException {
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-database-visibility"})
+    public void visibility_hasRoleForeign_fails() {
         final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
                 .isPublic(true)
                 .build();
 
+        /* mock */
+        when(userRepository.findByUsername(USER_2_USERNAME))
+                .thenReturn(Optional.of(USER_2));
+
         /* test */
-        visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_1_PRINCIPAL);
+        assertThrows(NotAllowedException.class, () -> {
+            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_2_PRINCIPAL);
+        });
     }
 
     @Test
-    @WithMockUser(username = USER_4_USERNAME, roles = {"RESEARCHER"})
-    public void transfer_researcherForeign_fails() {
+    @WithMockUser(username = USER_3_USERNAME)
+    public void transfer_noRole_fails() {
         final DatabaseTransferDto request = DatabaseTransferDto.builder()
                 .username(USER_4_USERNAME)
                 .build();
@@ -428,90 +247,70 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
                 .thenReturn(Optional.of(USER_4));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            databaseEndpoint.transfer(CONTAINER_1_ID, DATABASE_1_ID, request, USER_4_PRINCIPAL);
+        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
+            databaseEndpoint.transfer(CONTAINER_3_ID, DATABASE_3_ID, request, USER_3_PRINCIPAL);
         });
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void visibility_researcherForeignDatabase_fails() {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-database-owner"})
+    public void transfer_hasRoleForeign_fails() {
+        final DatabaseTransferDto request = DatabaseTransferDto.builder()
+                .username(USER_4_USERNAME)
                 .build();
 
+        /* mock */
+        when(userRepository.findByUsername(USER_2_USERNAME))
+                .thenReturn(Optional.of(USER_2));
+        when(databaseRepository.findById(DATABASE_1_ID))
+                .thenReturn(Optional.of(DATABASE_1));
+
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            visibility_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, DATABASE_2_DTO, request, USER_1_PRINCIPAL);
+            databaseEndpoint.transfer(CONTAINER_1_ID, DATABASE_1_ID, request, USER_2_PRINCIPAL);
         });
     }
 
     @Test
-    @WithMockUser(username = USER_4_USERNAME, roles = {"RESEARCHER"})
-    public void visibility_researcherForeign_fails() {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"})
+    public void transfer_hasRole_succeeds() throws UserNotFoundException, DatabaseNotFoundException, NotAllowedException {
+        final DatabaseTransferDto request = DatabaseTransferDto.builder()
+                .username(USER_4_USERNAME)
                 .build();
 
         /* mock */
+        when(userRepository.findByUsername(USER_1_USERNAME))
+                .thenReturn(Optional.of(USER_1));
         when(userRepository.findByUsername(USER_4_USERNAME))
                 .thenReturn(Optional.of(USER_4));
+        when(databaseRepository.findById(DATABASE_1_ID))
+                .thenReturn(Optional.of(DATABASE_1));
 
         /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_4_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void visibility_developer_succeeds() throws NotAllowedException, DatabaseNotFoundException {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
-                .build();
-
-        /* test */
-        visibility_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, DATABASE_2_DTO, request, USER_2_PRINCIPAL);
+        databaseEndpoint.transfer(CONTAINER_1_ID, DATABASE_1_ID, request, USER_1_PRINCIPAL);
     }
 
     @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void visibility_developerForeignDatabase_succeeds() throws NotAllowedException, DatabaseNotFoundException {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
-                .build();
-
-        /* test */
-        visibility_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, DATABASE_1_DTO, request, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void visibility_dataSteward_fails() {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"})
+    public void transfer_hasRoleUserNotExists_succeeds() {
+        final DatabaseTransferDto request = DatabaseTransferDto.builder()
+                .username("foobar")
                 .build();
 
-        /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            visibility_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, DATABASE_3_DTO, request, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void visibility_dataStewardForeignDatabase_fails() {
-        final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
-                .isPublic(true)
-                .build();
+        /* mock */
+        when(userRepository.findByUsername(USER_1_USERNAME))
+                .thenReturn(Optional.of(USER_1));
+        when(databaseRepository.findById(DATABASE_1_ID))
+                .thenReturn(Optional.of(DATABASE_1));
 
         /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            visibility_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, DATABASE_2_DTO, request, USER_3_PRINCIPAL);
+        assertThrows(UserNotFoundException.class, () -> {
+            databaseEndpoint.transfer(CONTAINER_1_ID, DATABASE_1_ID, request, USER_1_PRINCIPAL);
         });
     }
 
     @Test
+    @WithAnonymousUser
     public void findById_anonymous_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
         /* test */
@@ -520,13 +319,6 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymous2_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
-
-        /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, null);
-    }
-
-    @Test
     public void findById_anonymousNotFound_fails() {
 
         /* test */
@@ -536,18 +328,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void findById_anonymous2NotFound_fails() {
-
-        /* test */
-        assertThrows(DatabaseNotFoundException.class, () -> {
-            findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, null, null);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcherPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
+    public void findById_hasRole_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
 
         /* pre-condition */
         assertTrue(DATABASE_3_PUBLIC);
@@ -557,8 +339,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcherPublicForeignDatabase_succeeds() throws AccessDeniedException,
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
+    public void findById_hasRoleForeign_succeeds() throws AccessDeniedException,
             DatabaseNotFoundException {
 
         /* pre-condition */
@@ -568,99 +350,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
         findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
     }
 
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcherPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void findById_researcherPrivateForeignDatabase_succeeds() throws AccessDeniedException,
-            DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findById_developerPublicForeignDatabase_succeeds() throws AccessDeniedException,
-            DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"})
-    public void findById_developerPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findById_dataStewardPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findById_dataStewardPublicForeignDatabase_succeeds() throws AccessDeniedException,
-            DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL);
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void findById_dataStewardPrivateForeignDatabase_succeeds() throws AccessDeniedException,
-            DatabaseNotFoundException {
-
-        /* pre-condition */
-        assertFalse(DATABASE_2_PUBLIC);
-
-        /* test */
-        findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_3_PRINCIPAL);
-    }
-
-    @Test
-    public void delete_anonymous_fails() {
-
-        /* test */
-        assertThrows(AuthenticationCredentialsNotFoundException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, null, null);
-        });
-    }
-
     @Test
     @WithAnonymousUser
-    public void delete_anonymous2_fails() {
+    public void delete_anonymous_fails() {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
@@ -669,8 +361,8 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void delete_researcher_fails() {
+    @WithMockUser(username = USER_1_USERNAME)
+    public void delete_noRole_fails() {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
@@ -679,33 +371,14 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"})
-    public void delete_researcherForeignDatabase_fails() {
-
-        /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_USERNAME, USER_1_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void delete_dataSteward_fails() {
-
-        /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_USERNAME, USER_3_PRINCIPAL);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"})
-    public void delete_dataStewardForeignDatabase_fails() {
+    @Disabled
+    @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-database"})
+    public void delete_hasRole_succeeds() throws UserNotFoundException, BrokerVirtualHostGrantException,
+            DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException,
+            AmqpException, BrokerVirtualHostCreationException, ContainerNotFoundException, DatabaseMalformedException {
 
         /* test */
-        assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            delete_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, USER_3_USERNAME, USER_3_PRINCIPAL);
-        });
+        delete_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL);
     }
 
     /* ################################################################################################### */
@@ -768,7 +441,7 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest {
 
     public void visibility_generic(Long containerId, Container container, Long databaseId, Database database,
                                    DatabaseDto dto, DatabaseModifyVisibilityDto data, Principal principal)
-            throws NotAllowedException, DatabaseNotFoundException {
+            throws NotAllowedException, DatabaseNotFoundException, UserNotFoundException {
 
         /* mock */
         when(containerRepository.findById(containerId))
diff --git a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
index 0ff197662b..77d4d92898 100644
--- a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
+++ b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java
@@ -10,7 +10,6 @@ import at.tuwien.entities.database.DatabaseAccess;
 import at.tuwien.exception.AccessDeniedException;
 import at.tuwien.exception.NotAllowedException;
 import at.tuwien.repository.jpa.*;
-import at.tuwien.test.BaseTest;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.Test;
diff --git a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceComponentTest.java b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceComponentTest.java
index 06a0e20587..f1a930c9f3 100644
--- a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceComponentTest.java
+++ b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceComponentTest.java
@@ -7,13 +7,12 @@ import at.tuwien.config.*;
 import at.tuwien.entities.database.Database;
 import at.tuwien.repository.elastic.DatabaseIdxRepository;
 import at.tuwien.repository.jpa.ContainerRepository;
+import at.tuwien.repository.jpa.DatabaseRepository;
 import at.tuwien.repository.jpa.ImageRepository;
 import at.tuwien.repository.jpa.UserRepository;
 import at.tuwien.service.impl.MariaDbServiceImpl;
-import at.tuwien.test.BaseTest;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
-import org.apache.http.auth.BasicUserPrincipal;
 import org.junit.jupiter.api.*;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -23,7 +22,7 @@ import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.File;
-import java.security.Principal;
+import java.util.Optional;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.any;
@@ -45,16 +44,16 @@ public class DatabaseServiceComponentTest extends BaseUnitTest {
     private IndexConfig indexConfig;
 
     @MockBean
-    private DatabaseIdxRepository databaseIdxRepository;
+    private UserRepository userRepository;
 
-    @Autowired
+    @MockBean
     private ContainerRepository containerRepository;
 
-    @Autowired
-    private UserRepository userRepository;
+    @MockBean
+    private DatabaseRepository databaseRepository;
 
-    @Autowired
-    private ImageRepository imageRepository;
+    @MockBean
+    private DatabaseIdxRepository databaseIdxRepository;
 
     @Autowired
     private MariaDbServiceImpl databaseService;
@@ -81,8 +80,6 @@ public class DatabaseServiceComponentTest extends BaseUnitTest {
         afterEach();
         /* metadata database */
         h2Utils.runScript("schema.sql");
-        imageRepository.save(IMAGE_1);
-        userRepository.save(USER_1);
     }
 
     @AfterEach
@@ -112,15 +109,17 @@ public class DatabaseServiceComponentTest extends BaseUnitTest {
 
     protected void generic_create(Long containerId, DatabaseCreateDto createDto, Database database)
             throws Exception {
-        final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
 
         /* mock */
-        containerRepository.save(CONTAINER_1);
-        containerRepository.save(CONTAINER_2);
-        containerRepository.save(CONTAINER_3);
+        when(userRepository.findByUsername(USER_1_USERNAME))
+                .thenReturn(Optional.of(USER_1));
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
+        when(databaseRepository.save(any(Database.class)))
+                .thenReturn(DATABASE_3);
 
         /* test */
-        final Database response = databaseService.create(containerId, createDto, principal);
+        final Database response = databaseService.create(containerId, createDto, USER_1_PRINCIPAL);
         assertEquals(database.getName(), response.getName());
         assertEquals(containerId, database.getId());
     }
diff --git a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
index 4b2e2a5ca0..a048f537e3 100644
--- a/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
+++ b/dbrepo-database-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
@@ -27,6 +27,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 import java.io.File;
 import java.security.Principal;
 import java.sql.SQLException;
+import java.util.Optional;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.any;
@@ -48,20 +49,17 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
     private IndexConfig indexConfig;
 
     @MockBean
-    private DatabaseIdxRepository databaseIdxRepository;
-
-    @Autowired
-    private ContainerRepository containerRepository;
-
-    @Autowired
     private UserRepository userRepository;
 
-    @Autowired
-    private ImageRepository imageRepository;
+    @MockBean
+    private ContainerRepository containerRepository;
 
-    @Autowired
+    @MockBean
     private MariaDbServiceImpl databaseService;
 
+    @MockBean
+    private DatabaseIdxRepository databaseIdxRepository;
+
     @Autowired
     private MariaDbConfig mariaDbConfig;
 
@@ -85,9 +83,6 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
     public void beforeEach() {
         afterEach();
         DockerConfig.createAllNetworks();
-        /* metadata database */
-        imageRepository.save(IMAGE_1);
-        userRepository.save(USER_1);
     }
 
     @AfterEach
@@ -105,6 +100,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         MariaDbConfig.dropDatabase(CONTAINER_3_INTERNALNAME, DATABASE_3_INTERNALNAME, "root", "mariadb");
         when(databaseIdxRepository.save(any(DatabaseDto.class)))
                 .thenReturn(DATABASE_1_DTO);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_create(CONTAINER_3_ID, DATABASE_3_CREATE, DATABASE_3);
@@ -123,6 +120,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         when(databaseIdxRepository.save(any(DatabaseDto.class)))
                 .thenReturn(DATABASE_2_DTO)
                 .thenReturn(DATABASE_3_DTO);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_create(CONTAINER_2_ID, DATABASE_2_CREATE, DATABASE_2);
@@ -142,6 +141,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         when(databaseIdxRepository.save(any(DatabaseDto.class)))
                 .thenReturn(DATABASE_3_DTO)
                 .thenReturn(DATABASE_2_DTO);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_create(CONTAINER_3_ID, DATABASE_3_CREATE, DATABASE_3);
@@ -154,6 +155,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_insert(QUERY_4_STATEMENT, 1L);
@@ -166,6 +169,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_insert(QUERY_4_STATEMENT, 1L);
@@ -179,6 +184,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_system_insert("root", "mariadb");
@@ -190,6 +197,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         assertThrows(SQLException.class, () -> {
@@ -203,6 +212,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_user_insert("root", "mariadb");
@@ -214,6 +225,8 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
         /* mock */
         DockerConfig.createContainer(BIND_MUSICOLOGY, CONTAINER_3, CONTAINER_3_ENV);
         DockerConfig.startContainer(CONTAINER_3);
+        when(containerRepository.findById(CONTAINER_3_ID))
+                .thenReturn(Optional.of(CONTAINER_3));
 
         /* test */
         generic_user_insert("junit1", "junit1");
@@ -227,9 +240,6 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
 
         /* mock */
         mariaDbConfig.mockGrantUserPermissions(CONTAINER_3_INTERNALNAME, DATABASE_3, USER_1);
-        containerRepository.save(CONTAINER_1);
-        containerRepository.save(CONTAINER_2);
-        containerRepository.save(CONTAINER_3);
 
         /* test */
         final Long response = MariaDbConfig.mockSystemQueryInsert(CONTAINER_3_INTERNALNAME, DATABASE_3_INTERNALNAME, query);
@@ -241,11 +251,6 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
             throws Exception {
         final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
 
-        /* mock */
-        containerRepository.save(CONTAINER_1);
-        containerRepository.save(CONTAINER_2);
-        containerRepository.save(CONTAINER_3);
-
         /* test */
         final Database response = databaseService.create(containerId, createDto, principal);
         assertEquals(database.getName(), response.getName());
@@ -256,9 +261,6 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
 
         /* mock */
         mariaDbConfig.mockGrantUserPermissions(CONTAINER_3_INTERNALNAME, DATABASE_3, USER_1);
-        containerRepository.save(CONTAINER_1);
-        containerRepository.save(CONTAINER_2);
-        containerRepository.save(CONTAINER_3);
 
         /* test */
         final Long queryId = MariaDbConfig.mockSystemQueryInsert(CONTAINER_3_INTERNALNAME, DATABASE_3_INTERNALNAME,
@@ -270,9 +272,6 @@ public class DatabaseServiceIntegrationTest extends BaseUnitTest {
 
         /* mock */
         mariaDbConfig.mockGrantUserPermissions(CONTAINER_3_INTERNALNAME, DATABASE_3, USER_1);
-        containerRepository.save(CONTAINER_1);
-        containerRepository.save(CONTAINER_2);
-        containerRepository.save(CONTAINER_3);
 
         /* test */
         final Long queryId = MariaDbConfig.mockUserQueryInsert(CONTAINER_3_INTERNALNAME, DATABASE_3_INTERNALNAME,
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
index b425a856b7..3056c030b4 100644
--- a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
@@ -6,7 +6,7 @@ import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
 
-@Mapper(componentModel = "spring")
+@Mapper(componentModel = "spring", uses = {ImageMapper.class})
 public interface ContainerMapper {
 
     @Mappings({
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
index df3d18b7d8..183e146a6c 100644
--- a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java
@@ -28,7 +28,7 @@ import java.util.Locale;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
-@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class})
+@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class, ImageMapper.class})
 public interface DatabaseMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DatabaseMapper.class);
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
index 592103597a..30d5ff02e7 100644
--- a/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
@@ -1,5 +1,6 @@
 package at.tuwien.mapper;
 
+import at.tuwien.api.container.image.ImageDto;
 import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.entities.container.image.ContainerImageEnvironmentItem;
 import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType;
@@ -14,6 +15,9 @@ public interface ImageMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImageMapper.class);
 
+    /* keep */
+    ImageDto containerImageToImageDto(ContainerImage data);
+
     @Deprecated
     default Properties containerImageToProperties(ContainerImage data) throws ImageNotSupportedException {
         final Properties properties = new Properties();
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java b/dbrepo-database-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
new file mode 100644
index 0000000000..74d99176b0
--- /dev/null
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/repository/jpa/RealmRepository.java
@@ -0,0 +1,9 @@
+package at.tuwien.repository.jpa;
+
+import at.tuwien.entities.user.Realm;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RealmRepository extends JpaRepository<Realm, String>  {
+}
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
index 4c12336aa3..3aa6ab4ea3 100644
--- a/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java
@@ -68,10 +68,6 @@ public class AccessServiceImpl extends HibernateConnector implements AccessServi
         final Container container = database.getContainer();
         final User user = userService.findByUsername(accessDto.getUsername());
         log.trace("give access to user with username {}", user.getUsername());
-        if (database.getOwner().getUsername().equals(user.getUsername())) {
-            log.error("Failed to give access to user with username {}, is already database owner", user.getUsername());
-            throw new NotAllowedException("Failed give access");
-        }
         if (databaseAccessRepository.findByDatabaseIdAndUsername(databaseId, accessDto.getUsername()).isPresent()) {
             log.error("Failed to give access to user with username {}, has already permission", accessDto.getUsername());
             throw new NotAllowedException("Failed to give access");
diff --git a/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java b/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java
index fd055f90ed..75b54f4fe7 100644
--- a/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java
+++ b/dbrepo-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java
@@ -1,6 +1,7 @@
 package at.tuwien.service.impl;
 
 import at.tuwien.api.database.DatabaseCreateDto;
+import at.tuwien.api.database.DatabaseDto;
 import at.tuwien.api.database.DatabaseModifyVisibilityDto;
 import at.tuwien.api.database.DatabaseTransferDto;
 import at.tuwien.entities.container.Container;
diff --git a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/Realm.java
similarity index 78%
rename from dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java
rename to dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/Realm.java
index 57b472396c..c87b90bc69 100644
--- a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/auth/Realm.java
+++ b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/Realm.java
@@ -1,9 +1,10 @@
-package at.tuwien.entities.auth;
+package at.tuwien.entities.user;
 
 import lombok.*;
 import org.hibernate.annotations.GenericGenerator;
 
 import javax.persistence.*;
+import java.util.List;
 
 @Data
 @Entity
@@ -13,6 +14,9 @@ import javax.persistence.*;
 @ToString
 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
 @Table(name = "realm")
+@NamedQueries({
+        @NamedQuery(name = "Realm.findAll", query = "select r from Realm r where r.name = 'dbrepo'")
+})
 public class Realm {
 
     @Id
diff --git a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
index 5aec996876..2d36a68aff 100644
--- a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
+++ b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
@@ -5,7 +5,6 @@ import at.tuwien.entities.database.Database;
 import at.tuwien.entities.identifier.Identifier;
 import lombok.*;
 import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.annotations.Immutable;
 import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
@@ -19,7 +18,15 @@ import java.util.List;
 @ToString
 @EntityListeners(AuditingEntityListener.class)
 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
-@Table(name = "user_entity")
+@Table(name = "user_entity", uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"REALM_ID", "EMAIL"}),
+        @UniqueConstraint(columnNames = {"REALM_ID", "USERNAME"})
+})
+@NamedQueries({
+        @NamedQuery(name = "User.findAll", query = "select u from User u join Realm r on r.name = 'dbrepo'"),
+        @NamedQuery(name = "User.findById", query = "select u from User u join Realm r on r.name = 'dbrepo' and u.id = ?1"),
+        @NamedQuery(name = "User.findByUsername", query = "select u from User u join Realm r on r.name = 'dbrepo' and u.username = ?1")
+})
 public class User {
 
     @Id
@@ -29,7 +36,7 @@ public class User {
     @Column(name = "ID", nullable = false, columnDefinition = "VARCHAR(36)")
     private String id;
 
-    @Column(unique = true, nullable = false)
+    @Column(nullable = false)
     private String username;
 
     @Column(name = "FIRST_NAME")
@@ -41,7 +48,7 @@ public class User {
     @Column(name = "REALM_ID")
     private String realmId;
 
-    @Column(unique = true, nullable = false)
+    @Column(nullable = false)
     private String email;
 
     @Column(nullable = false)
diff --git a/dbrepo-metadata-db/test/src/main/java/at/tuwien/config/RabbitMqConfig.java b/dbrepo-metadata-db/test/src/main/java/at/tuwien/config/RabbitMqConfig.java
index d0bd6ca9e7..e4000c7a04 100644
--- a/dbrepo-metadata-db/test/src/main/java/at/tuwien/config/RabbitMqConfig.java
+++ b/dbrepo-metadata-db/test/src/main/java/at/tuwien/config/RabbitMqConfig.java
@@ -4,6 +4,7 @@ import at.tuwien.api.amqp.ConsumerDto;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.codec.binary.Base64;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.http.*;
@@ -23,7 +24,7 @@ public class RabbitMqConfig {
     private final RestTemplate restTemplate;
 
     @Autowired
-    public RabbitMqConfig(RestTemplate restTemplate) {
+    public RabbitMqConfig(@Qualifier("brokerRestTemplate") RestTemplate restTemplate) {
         this.restTemplate = restTemplate;
     }
 
diff --git a/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java
index 683e07b1ff..50bd567e0a 100644
--- a/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -28,6 +28,7 @@ import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey;
 import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference;
 import at.tuwien.entities.database.table.constraints.unique.Unique;
 import at.tuwien.entities.identifier.*;
+import at.tuwien.entities.user.Realm;
 import at.tuwien.entities.user.User;
 import at.tuwien.entities.user.UserAttribute;
 import at.tuwien.querystore.Query;
@@ -38,6 +39,7 @@ import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType;
 import at.tuwien.entities.database.table.Table;
 import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.database.table.columns.TableColumnType;
+import at.tuwien.utils.ArrayUtil;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -47,7 +49,6 @@ import com.github.dockerjava.api.model.HealthCheck;
 import java.math.BigInteger;
 import java.security.Principal;
 import java.time.Instant;
-import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -86,31 +87,76 @@ import static java.time.temporal.ChronoUnit.*;
  * Database 4 (Public, User 4)
  * <ul>
  * </ul>
+ * <br />
+ * User 1 (authorities=default researcher)
+ * <br />
+ * User 2 (authorities=default developer)
+ * <br />
+ * User 3 (authorities=empty)
  */
 public abstract class BaseTest {
 
-    public final static String[] DEFAULT_RESEARCHER_ROLES = new String[]{"default-container-handling",
-            "create-container", "list-containers", "modify-container-state", "find-container",
-            "default-database-handling", "update-database-access", "modify-database-visibility", "create-database",
-            "modify-database-owner", "delete-database-access", "check-database-access", "list-databases",
-            "create-database-access", "find-database", "default-identifier-handling", "create-identifier",
-            "find-identifier", "list-identifiers", "default-query-handling", "view-table-data", "execute-query",
-            "view-table-history", "list-database-views", "list-queries", "view-database-view-data", "export-query-data",
-            "find-query", "create-database-view", "delete-database-view", "delete-table-data", "export-table-data",
-            "persist-query", "re-execute-query", "insert-table-data", "find-database-view", "default-table-handling",
-            "list-tables", "create-table", "modify-table-column-semantics", "find-table", "default-user-handling",
-            "modify-user-theme", "modify-user-information", "default-researcher-roles", "default-user-handling",
-            "default-identifier-handling", "default-database-handling", "default-container-handling",
-            "default-table-handling", "default-query-handling"};
+    public final static String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling",
+            "create-container", "list-containers", "modify-container-state", "find-container"};
+
+    public final static String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling",
+            "modify-foreign-container-state", "delete-container"};
+
+    public final static String[] DEFAULT_DATABASE_HANDLING = new String[]{"default-database-handling",
+            "update-database-access", "modify-database-visibility", "create-database", "modify-database-owner",
+            "delete-database-access", "check-database-access", "list-databases",
+            "create-database-access", "find-database"};
+
+    public final static String[] ESCALATED_DATABASE_HANDLING = new String[]{"escalated-database-handling",
+            "delete-database"};
+
+    public final static String[] DEFAULT_IDENTIFIER_HANDLING = new String[]{"default-identifier-handling",
+            "create-identifier", "find-identifier", "list-identifiers"};
+
+    public final static String[] ESCALATED_IDENTIFIER_HANDLING = new String[]{"escalated-identifier-handling",
+            "modify-identifier-metadata", "delete-identifier"};
+
+    public final static String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data",
+            "execute-query", "view-table-history", "list-database-views", "list-queries", "view-database-view-data",
+            "export-query-data", "find-query", "create-database-view", "delete-database-view", "delete-table-data",
+            "export-table-data", "persist-query", "re-execute-query", "insert-table-data", "find-database-view"};
+
+    public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"};
+
+    public final static String[] DEFAULT_TABLE_HANDLING = new String[]{"default-table-handling",
+            "list-tables", "create-table", "modify-table-column-semantics", "find-table"};
+
+    public final static String[] ESCALATED_TABLE_HANDLING = new String[]{"escalated-table-handling",
+            "delete-table"};
+
+    public final static String[] DEFAULT_USER_HANDLING = new String[]{"default-user-handling", "modify-user-theme",
+            "modify-user-information"};
+
+    public final static String[] DEFAULT_RESEARCHER_ROLES = ArrayUtil.merge(List.of(new String[]{"default-researcher-roles"},
+            DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING,
+            DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING));
+
+    public final static String[] DEFAULT_DEVELOPER_ROLES = ArrayUtil.merge(List.of(new String[]{"default-developer-roles"},
+            DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING,
+            DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING, ESCALATED_CONTAINER_HANDLING, ESCALATED_DATABASE_HANDLING,
+            ESCALATED_IDENTIFIER_HANDLING, ESCALATED_QUERY_HANDLING, ESCALATED_TABLE_HANDLING));
 
     public final static List<GrantedAuthorityDto> AUTHORITY_DEFAULT_RESEARCHER_ROLES = Arrays.stream(DEFAULT_RESEARCHER_ROLES)
             .map(GrantedAuthorityDto::new)
             .collect(Collectors.toList());
 
+    public final static List<GrantedAuthorityDto> AUTHORITY_DEFAULT_DEVELOPER_ROLES = Arrays.stream(DEFAULT_DEVELOPER_ROLES)
+            .map(GrantedAuthorityDto::new)
+            .collect(Collectors.toList());
+
     public final static List<GrantedAuthority> AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES = AUTHORITY_DEFAULT_RESEARCHER_ROLES.stream()
             .map(a -> new SimpleGrantedAuthority(a.getAuthority()))
             .collect(Collectors.toList());
 
+    public final static List<GrantedAuthority> AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES = AUTHORITY_DEFAULT_DEVELOPER_ROLES.stream()
+            .map(a -> new SimpleGrantedAuthority(a.getAuthority()))
+            .collect(Collectors.toList());
+
     public final static UserThemeSetDto USER_THEME_DARK_DTO = UserThemeSetDto.builder()
             .themeDark(true)
             .build();
@@ -119,6 +165,16 @@ public abstract class BaseTest {
             .themeDark(false)
             .build();
 
+    public final static String REALM_DBREPO_ID = "6264bf7b-d1d3-4562-9c07-ce4364a8f9d3";
+    public final static String REALM_DBREPO_NAME = "dbrepo";
+    public final static Boolean REALM_DBREPO_ENABLED = true;
+
+    public final static Realm REALM_DBREPO = Realm.builder()
+            .id(REALM_DBREPO_ID)
+            .name(REALM_DBREPO_NAME)
+            .enabled(REALM_DBREPO_ENABLED)
+            .build();
+
     public final static String USER_BROKER_USERNAME = "guest";
     public final static String USER_BROKER_PASSWORD = "guest";
 
@@ -140,9 +196,11 @@ public abstract class BaseTest {
     public final static String USER_1_TITLES_BEFORE = "Dr.";
     public final static String USER_1_TITLES_AFTER = "MSc BSc";
     public final static Boolean USER_1_VERIFIED = false;
+    public final static Boolean USER_1_ENABLED = true;
     public final static Boolean USER_1_THEME_DARK = false;
     public final static Instant USER_1_CREATED = Instant.ofEpochSecond(1677399441) /* 2023-02-26 08:17:21 (UTC) */;
     public final static Instant USER_1_LAST_MODIFIED = USER_1_CREATED;
+    public final static String USER_1_REALM_ID = REALM_DBREPO_ID;
 
     public final static List<UserAttribute> USER_1_ATTRIBUTES = List.of(UserAttribute.builder()
                     .id("c466a105-5bbd-4afc-87ae-751d5037d9ab")
@@ -190,7 +248,8 @@ public abstract class BaseTest {
             .firstname(USER_1_FIRSTNAME)
             .lastname(USER_1_LASTNAME)
             .emailVerified(USER_1_VERIFIED)
-            .attributes(USER_1_ATTRIBUTES)
+            .enabled(USER_1_ENABLED)
+            .realmId(USER_1_REALM_ID)
             .build();
 
     public final static UserDto USER_1_DTO = UserDto.builder()
@@ -240,9 +299,11 @@ public abstract class BaseTest {
     public final static String USER_2_PASSWORD = "s3cr3t1nf0rm4t10n";
     public final static String USER_2_DATABASE_PASSWORD = "*9AA70A8B0EEFAFCB5BED5BDEF6EE264D5DA915AE" /* junit2 */;
     public final static Boolean USER_2_VERIFIED = true;
+    public final static Boolean USER_2_ENABLED = true;
     public final static Boolean USER_2_THEME_DARK = false;
     public final static Instant USER_2_CREATED = Instant.ofEpochSecond(1677399528) /* 2023-02-26 08:18:48 (UTC) */;
     public final static Instant USER_2_LAST_MODIFIED = USER_1_CREATED;
+    public final static String USER_2_REALM_ID = REALM_DBREPO_ID;
 
     public final static List<UserAttribute> USER_2_ATTRIBUTES = List.of(UserAttribute.builder()
                     .id("23da2c08-cb8a-4e18-a7f0-70c30de2771e")
@@ -291,6 +352,8 @@ public abstract class BaseTest {
             .firstname(USER_2_FIRSTNAME)
             .lastname(USER_2_LASTNAME)
             .emailVerified(USER_2_VERIFIED)
+            .enabled(USER_2_ENABLED)
+            .realmId(USER_2_REALM_ID)
             .build();
 
     public final static UserDto USER_2_DTO = UserDto.builder()
@@ -313,7 +376,7 @@ public abstract class BaseTest {
             .username(USER_2_USERNAME)
             .email(USER_2_EMAIL)
             .password(USER_2_PASSWORD)
-            .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
+            .authorities(AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES)
             .build();
 
     public final static at.tuwien.api.amqp.UserDetailsDto USER_2_DETAILS_DTO = at.tuwien.api.amqp.UserDetailsDto.builder()
@@ -334,8 +397,10 @@ public abstract class BaseTest {
     public final static String USER_3_PASSWORD = "password";
     public final static String USER_3_DATABASE_PASSWORD = "*D65FCA043964B63E849DD6334699ECB065905DA4" /* junit3 */;
     public final static Boolean USER_3_VERIFIED = true;
+    public final static Boolean USER_3_ENABLED = true;
     public final static Boolean USER_3_THEME_DARK = false;
     public final static Instant USER_3_CREATED = Instant.ofEpochSecond(1677399559) /* 2023-02-26 08:19:19 (UTC) */;
+    public final static String USER_3_REALM_ID = REALM_DBREPO_ID;
 
     public final static User USER_3 = User.builder()
             .id(USER_3_ID)
@@ -343,6 +408,8 @@ public abstract class BaseTest {
             .email(USER_3_EMAIL)
             .emailVerified(true)
             .databasePassword(USER_3_DATABASE_PASSWORD)
+            .enabled(USER_3_ENABLED)
+            .realmId(USER_3_REALM_ID)
             .build();
 
     public final static UserDto USER_3_DTO = UserDto.builder()
@@ -358,7 +425,7 @@ public abstract class BaseTest {
             .username(USER_3_USERNAME)
             .email(USER_3_EMAIL)
             .password(USER_3_PASSWORD)
-            .authorities(List.of(new SimpleGrantedAuthority("ROLE_DATA_STEWARD")))
+            .authorities(List.of())
             .build();
 
     public final static Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS,
@@ -379,8 +446,10 @@ public abstract class BaseTest {
     public final static String USER_4_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit4 */;
     public final static String USER_4_EMAIL = "junit4@ossdip.at";
     public final static Boolean USER_4_VERIFIED = true;
+    public final static Boolean USER_4_ENABLED = true;
     public final static Boolean USER_4_THEME_DARK = false;
     public final static Instant USER_4_CREATED = Instant.ofEpochSecond(1677399592) /* 2023-02-26 08:19:52 (UTC) */;
+    public final static String USER_4_REALM_ID = REALM_DBREPO_ID;
 
     public final static User USER_4 = User.builder()
             .id(USER_4_ID)
@@ -388,6 +457,8 @@ public abstract class BaseTest {
             .email(USER_4_EMAIL)
             .emailVerified(USER_4_VERIFIED)
             .databasePassword(USER_4_DATABASE_PASSWORD)
+            .enabled(USER_4_ENABLED)
+            .realmId(USER_4_REALM_ID)
             .build();
 
     public final static UserDto USER_4_DTO = UserDto.builder()
@@ -421,6 +492,7 @@ public abstract class BaseTest {
     public final static Boolean USER_5_VERIFIED = true;
     public final static Boolean USER_5_THEME_DARK = false;
     public final static Instant USER_5_CREATED = Instant.ofEpochSecond(1677399592) /* 2023-02-26 08:19:52 (UTC) */;
+    public final static String USER_5_REALM_ID = REALM_DBREPO_ID;
 
     public final static User USER_5 = User.builder()
             .id(USER_5_ID)
@@ -428,6 +500,7 @@ public abstract class BaseTest {
             .email(USER_5_EMAIL)
             .emailVerified(USER_5_VERIFIED)
             .databasePassword(USER_5_DATABASE_PASSWORD)
+            .realmId(USER_5_REALM_ID)
             .build();
 
     public final static UserDto USER_5_DTO = UserDto.builder()
diff --git a/dbrepo-metadata-db/test/src/main/java/at/tuwien/utils/ArrayUtil.java b/dbrepo-metadata-db/test/src/main/java/at/tuwien/utils/ArrayUtil.java
new file mode 100644
index 0000000000..336206728c
--- /dev/null
+++ b/dbrepo-metadata-db/test/src/main/java/at/tuwien/utils/ArrayUtil.java
@@ -0,0 +1,16 @@
+package at.tuwien.utils;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ArrayUtil {
+
+    public static String[] merge(List<String[]> list) {
+        final List<String> out = new LinkedList<>();
+        list.stream()
+                .forEach(roles -> out.addAll(Arrays.asList(roles)));
+        return out.toArray(new String[]{});
+    }
+
+}
diff --git a/dbrepo-ui/api/database.service.js b/dbrepo-ui/api/database.service.js
index 0b91b04637..50aefa4251 100644
--- a/dbrepo-ui/api/database.service.js
+++ b/dbrepo-ui/api/database.service.js
@@ -159,6 +159,36 @@ class DatabaseService {
         })
     })
   }
+
+  createView (id, databaseId, data) {
+    return new Promise((resolve, reject) => {
+      api.post(`/api/container/${id}/database/${databaseId}/view`, data, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const view = response.data
+          console.debug('response view', view)
+          resolve(view)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to delete view', error)
+          Vue.$toast.error(`[${code}] Failed to delete view: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  deleteView (id, databaseId, viewId) {
+    return new Promise((resolve, reject) => {
+      api.delete(`/api/container/${id}/database/${databaseId}/view/${viewId}`, { headers: { Accept: 'application/json' } })
+        .then(() => resolve())
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to delete view', error)
+          Vue.$toast.error(`[${code}] Failed to delete view: ${message}`)
+          reject(error)
+        })
+    })
+  }
 }
 
 export default new DatabaseService()
diff --git a/dbrepo-ui/api/identifier.service.js b/dbrepo-ui/api/identifier.service.js
index f35bcd886e..a7b739d804 100644
--- a/dbrepo-ui/api/identifier.service.js
+++ b/dbrepo-ui/api/identifier.service.js
@@ -2,7 +2,25 @@ import Vue from 'vue'
 import api from '@/api'
 
 class IdentifierService {
-  findPid (id) {
+  findAll (databaseId, type) {
+    return new Promise((resolve, reject) => {
+      const delim = databaseId !== null && type !== null ? '&' : '?'
+      api.get(`/api/identifier${databaseId !== null ? `?dbid=${databaseId}` : ''}${type !== null ? `${delim}type=${type}` : ''}`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const identifiers = response.data
+          console.debug('response identifiers', identifiers)
+          resolve(identifiers)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load identifiers', error)
+          Vue.$toast.error(`[${code}] Failed to load identifiers: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  findOne (id) {
     return new Promise((resolve, reject) => {
       api.get(`/api/pid/${id}`, { headers: { Accept: 'application/json' } })
         .then((response) => {
diff --git a/dbrepo-ui/api/middleware.service.js b/dbrepo-ui/api/middleware.service.js
index 165013f496..ffa7bbf2b8 100644
--- a/dbrepo-ui/api/middleware.service.js
+++ b/dbrepo-ui/api/middleware.service.js
@@ -20,6 +20,23 @@ class MiddlewareService {
         })
     })
   }
+
+  buildQuery (data) {
+    return new Promise((resolve, reject) => {
+      axios.post('/server-middleware/query/build', data, { headers: { 'Content-Type': 'multipart/form-data' } })
+        .then((response) => {
+          const file = response.data
+          console.debug('response file', file)
+          resolve(file)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to create database', error)
+          Vue.$toast.error(`[${code}] Failed to create database: ${message}`)
+          reject(error)
+        })
+    })
+  }
 }
 
 export default new MiddlewareService()
diff --git a/dbrepo-ui/api/query.service.js b/dbrepo-ui/api/query.service.js
index d74601bd53..1e467a5674 100644
--- a/dbrepo-ui/api/query.service.js
+++ b/dbrepo-ui/api/query.service.js
@@ -2,9 +2,9 @@ import Vue from 'vue'
 import api from '@/api'
 
 class QueryService {
-  findAll (id, databaseId) {
+  findAll (id, databaseId, persisted) {
     return new Promise((resolve, reject) => {
-      api.get(`/api/container/${id}/database/${databaseId}/query`, { headers: { Accept: 'application/json' } })
+      api.get(`/api/container/${id}/database/${databaseId}/query${persisted === null ? '' : `?persisted=${persisted}`}`, { headers: { Accept: 'application/json' } })
         .then((response) => {
           const queries = response.data
           console.debug('response queries', queries)
diff --git a/dbrepo-ui/api/table.service.js b/dbrepo-ui/api/table.service.js
index 3b0b55379c..d5fc87b38b 100644
--- a/dbrepo-ui/api/table.service.js
+++ b/dbrepo-ui/api/table.service.js
@@ -57,6 +57,19 @@ class TableService {
         })
     })
   }
+
+  deleteTuple (id, databaseId, tableId, data) {
+    return new Promise((resolve, reject) => {
+      api.delete(`/api/container/${id}/database/${databaseId}/table/${tableId}/data`, { headers: { Accept: 'application/json' }, data })
+        .then(() => resolve())
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to delete table tuple', error)
+          Vue.$toast.error(`[${code}] Failed to delete table tuple: ${message}`)
+          reject(error)
+        })
+    })
+  }
 }
 
 export default new TableService()
diff --git a/dbrepo-ui/components/QueryList.vue b/dbrepo-ui/components/QueryList.vue
index 200b37fb06..1bead29f29 100644
--- a/dbrepo-ui/components/QueryList.vue
+++ b/dbrepo-ui/components/QueryList.vue
@@ -68,7 +68,9 @@
 </template>
 
 <script>
-import { formatTimestampUTCLabel, formatUser } from '@/utils'
+import { formatTimestampUTCLabel } from '@/utils'
+import QueryService from '@/api/query.service'
+import IdentifierService from '@/api/identifier.service'
 
 export default {
   data () {
@@ -130,39 +132,25 @@ export default {
     this.simulateProgress()
   },
   methods: {
-    formatCreator (creator) {
-      return formatUser(creator)
+    loadIdentifiers () {
+      this.loadingIdentifiers = true
+      IdentifierService.findAll(this.$route.params.database_id, 'subset')
+        .then((identifiers) => {
+          this.identifiers = identifiers
+        })
+        .finally(() => {
+          this.loadingIdentifiers = false
+        })
     },
-    async loadIdentifiers () {
-      try {
-        this.loadingIdentifiers = true
-        const res = await this.$axios.get(`/api/identifier?dbid=${this.$route.params.database_id}&type=subset`, this.config)
-        this.identifiers = res.data
-        console.debug('identifiers', this.identifiers)
-      } catch (error) {
-        this.error = true
-        console.error('Failed to load identifiers', error)
-        const { message } = error.response
-        this.$toast.error(`Failed to load identifiers: ${message}`)
-      }
-      this.loadingIdentifiers = false
-    },
-    async loadQueries () {
-      try {
-        this.loadingQueries = true
-        const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query?persisted=true`, this.config)
-        this.queries = res.data
-        console.debug('queries', this.queries)
-      } catch (error) {
-        const { status, data } = error.response
-        const { message } = data
-        if (status !== 405) {
-          this.error = true
-          console.error('Connection to query store failed', error)
-          this.$toast.error(`Failed to connect to query store: ${message}`)
-        }
-      }
-      this.loadingQueries = false
+    loadQueries () {
+      this.loadingQueries = true
+      QueryService.findAll(this.$route.params.container_id, this.$route.params.database_id, true)
+        .then((queries) => {
+          this.queries = queries
+        })
+        .finally(() => {
+          this.loadingQueries = false
+        })
     },
     title (query) {
       if (query.identifier === null) {
diff --git a/dbrepo-ui/components/TableToolbar.vue b/dbrepo-ui/components/TableToolbar.vue
index 6203f51642..b4006495ac 100644
--- a/dbrepo-ui/components/TableToolbar.vue
+++ b/dbrepo-ui/components/TableToolbar.vue
@@ -54,6 +54,7 @@
 <script>
 import EditTuple from '@/components/dialogs/EditTuple'
 import { isResearcher } from '@/utils'
+import TableService from '@/api/table.service'
 
 export default {
   components: {
@@ -172,29 +173,10 @@ export default {
     isResearcher () {
       return isResearcher(this.user)
     },
-    config () {
-      if (this.token === null) {
-        return {}
-      }
-      return {
-        headers: { Authorization: `Bearer ${this.token}` }
-      }
-    },
-    silentConfig () {
-      return {
-        headers: this.config.headers,
-        progress: false
-      }
-    },
     databaseTooltip () {
       return this.database.is_public ? 'Public' : 'Private'
     }
   },
-  watch: {
-    selection (newVersion, oldVersion) {
-      console.info('selected new', this.selection)
-    }
-  },
   methods: {
     addTuple () {
       const data = {}
@@ -216,33 +198,24 @@ export default {
       }
       this.pickVersionDialog = true
     },
-    async deleteItems () {
+    deleteItems () {
       if (this.selection.length < 1) {
         return
       }
-      try {
-        this.loadingDelete = true
-        for (const select of this.selection) {
-          /* remove in container */
-          const constraints = {}
-          this.table.columns
-            .filter(c => c.is_primary_key)
-            .forEach((c) => {
-              constraints[c.internal_name] = select[c.internal_name]
-            })
-          await this.$axios.delete(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data`, {
-            headers: { Authorization: `Bearer ${this.token}` },
-            data: { keys: constraints }
+      this.loadingDelete = true
+      for (const select of this.selection) {
+        /* remove in container */
+        const constraints = {}
+        this.table.columns
+          .filter(c => c.is_primary_key)
+          .forEach((c) => {
+            constraints[c.internal_name] = select[c.internal_name]
+          })
+        TableService.deleteTuple(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.table_id, { keys: constraints })
+          .then(() => {
+            this.$toast.success(`Deleted ${this.selection.length} rows(s)`)
+            this.$emit('modified', { success: true, action: 'delete' })
           })
-        }
-        console.info(`Deleted ${this.selection.length} rows(s)`)
-        this.$toast.success(`Deleted ${this.selection.length} rows(s)`)
-        this.$emit('modified', { success: true, action: 'delete' })
-      } catch (error) {
-        console.error('Failed to delete rows', error)
-        const { data } = error.response
-        const { message } = data
-        this.$toast.error(`Failed to delete rows: ${message}`)
       }
       this.loadingDelete = false
     },
diff --git a/dbrepo-ui/components/UserToolbar.vue b/dbrepo-ui/components/UserToolbar.vue
index f8e7b086ca..462b438496 100644
--- a/dbrepo-ui/components/UserToolbar.vue
+++ b/dbrepo-ui/components/UserToolbar.vue
@@ -17,24 +17,12 @@
 </template>
 
 <script>
-import { isDeveloper, isResearcher } from '@/utils'
 
 export default {
   data () {
     return {
       tab: null
     }
-  },
-  computed: {
-    user () {
-      return this.$store.state.user
-    },
-    isDeveloper () {
-      return isDeveloper(this.user)
-    },
-    isResearcher () {
-      return isResearcher(this.user)
-    }
   }
 }
 </script>
diff --git a/dbrepo-ui/components/ViewList.vue b/dbrepo-ui/components/ViewList.vue
index b2aff93d4e..340a624c57 100644
--- a/dbrepo-ui/components/ViewList.vue
+++ b/dbrepo-ui/components/ViewList.vue
@@ -24,6 +24,7 @@
 
 <script>
 import { formatTimestampUTCLabel } from '@/utils'
+import DatabaseService from '@/api/database.service'
 
 export default {
   data () {
@@ -81,52 +82,22 @@ export default {
       }
       return formatTimestampUTCLabel(this.viewDetails.created)
     },
-    viewVisibility () {
-      return this.viewDetails.is_public ? 'Public' : 'Private'
-    },
     canDelete () {
-      console.debug(this.viewDetails.created_by, '=?=', this.user.id)
       return this.viewDetails.created_by === this.user.id
     }
   },
   mounted () {
   },
   methods: {
-    async details (table) {
-      if (table.id === this.viewDetails.id) {
-        /* prevent weird glitch of opening and collapsing simultaneously */
-        return
-      }
-      this.attemptedLoadingConsumers = false
-      /* use cache */
-      this.viewDetails = table
-      /* load remaining info */
-      if (this.isPublicOrOwner) {
-        try {
-          this.loadingDetails = true
-          const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${table.id}`, this.config)
-          this.viewDetails = res.data
-          console.debug('table details', this.viewDetails)
-          if (table.id) {
-            this.openPanelByTableId(table.id)
-            await this.consumerDetails(this.viewDetails.topic)
-          }
-        } catch (err) {
-          this.$toast.error('Failed to load table details')
-          console.error('Failed to load table details', err)
-        }
-        this.loadingDetails = false
-      }
-    },
-    async deleteView (view) {
-      try {
-        const res = await this.$axios.$delete(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/view/${view.id}`, this.config)
-        console.debug('deleted view', res.index)
-        this.$toast.success(`Successfully deleted view with id ${view.id}`)
-      } catch (err) {
-        this.$toast.error('Failed to delete view')
-        console.error('Failed to delete view')
-      }
+    deleteView (view) {
+      this.loading = true
+      DatabaseService.deleteView(this.$route.params.container_id, this.$route.params.database_id, view.id)
+        .then(() => {
+          this.$toast.success(`Successfully deleted view with id ${view.id}`)
+        })
+        .finally(() => {
+          this.loading = false
+        })
     }
   }
 }
diff --git a/dbrepo-ui/components/query/Builder.vue b/dbrepo-ui/components/query/Builder.vue
index e8a93314c1..970cfbd218 100644
--- a/dbrepo-ui/components/query/Builder.vue
+++ b/dbrepo-ui/components/query/Builder.vue
@@ -148,6 +148,9 @@
 </template>
 
 <script>
+import DatabaseService from '@/api/database.service'
+import MiddlewareService from '@/api/middleware.service'
+
 export default {
   props: {
     mode: {
@@ -316,58 +319,35 @@ export default {
       }
       await this.$refs.queryResults.executeFirstTime(this, this.sql, this.timestamp)
     },
-    async createView () {
+    createView () {
       this.loadingQuery = true
-      try {
-        this.view.query = this.sql
-        console.debug('create view payload', this.view)
-        const res = await this.$axios.post(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/view`, this.view, this.config)
-        this.resultId = res.data.id
-        console.debug('view', res.data)
-        await this.loadDatabase()
-      } catch (error) {
-        console.error('Failed to create view', error)
-        const { statusText } = error.response
-        this.$toast.error(`Failed to create view: ${statusText}`)
-      }
-      this.loadingQuery = false
-      await Promise.all([this.$refs.queryResults.reExecute(this.resultId), this.$refs.queryResults.reExecuteCount(this.resultId)])
+      DatabaseService.createView(this.$route.params.container_id, this.$route.params.database_id, this.view)
+        .then(async (view) => {
+          this.resultId = view.id
+          await this.$store.dispatch('reloadDatabase')
+          await Promise.all([this.$refs.queryResults.reExecute(this.resultId), this.$refs.queryResults.reExecuteCount(this.resultId)])
+        })
+        .finally(() => {
+          this.loadingQuery = false
+        })
     },
-    async buildQuery () {
+    buildQuery () {
       if (!this.table) {
         return
       }
-      const url = '/server-middleware/query/build'
       const data = {
         table: this.table.internal_name,
         select: this.select.map(s => s.internal_name),
         clauses: this.clauses
       }
-      try {
-        this.loadingQuery = true
-        const res = await this.$axios.post(url, data, { progress: false })
-        if (res && !res.error) {
-          this.query = res.data
-        }
-      } catch (e) {
-        console.log(e)
-      }
-      this.loadingQuery = false
-    },
-    async loadDatabase () {
-      if (!this.$route.params.container_id || !this.$route.params.database_id) {
-        return
-      }
-      try {
-        this.loading = true
-        const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}`, this.config)
-        this.$store.commit('SET_DATABASE', res.data)
-        console.debug('database', this.database)
-      } catch (err) {
-        console.error('Could not load database', err)
-        this.$toast.error('Could not load database')
-      }
-      this.loading = false
+      this.loadingQuery = true
+      MiddlewareService.buildQuery(data)
+        .then((query) => {
+          this.query = query
+        })
+        .finally(() => {
+          this.loadingQuery = false
+        })
     }
   }
 }
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index ffb5a9430e..b455e83051 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -296,7 +296,7 @@ export default {
         return
       }
       this.loading = true
-      IdentifierService.findPid(this.database.identifier.id)
+      IdentifierService.findOne(this.database.identifier.id)
         .then((identifier) => {
           this.database.identifier = identifier
           this.$store.commit('SET_DATABASE', this.database)
-- 
GitLab