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