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 4b93e2f751ad1f2614bd239ae644733855b7e417..70f13b1f227608b48d96b7d29362c6ae483c9d68 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 @@ -16,6 +16,7 @@ import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableCsvDto; import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.foreignKey.ForeignKeyCreateDto; import at.tuwien.api.identifier.*; @@ -23,6 +24,7 @@ import at.tuwien.api.user.*; import at.tuwien.entities.container.image.ContainerImageDate; import at.tuwien.entities.database.*; import at.tuwien.entities.database.table.columns.TableColumnConcept; +import at.tuwien.entities.database.table.columns.TableColumnUnit; import at.tuwien.entities.database.table.constraints.Constraints; import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; @@ -1651,53 +1653,32 @@ public abstract class BaseTest { public final static Instant TABLE_8_CREATED = Instant.ofEpochSecond(1688400185) /* 2023-02-26 08:29:35 (UTC) */; public final static Instant TABLE_8_LAST_MODIFIED = Instant.ofEpochSecond(1688400185) /* 2023-02-26 08:29:35 (UTC) */; - public final static Table TABLE_8 = Table.builder() - .id(TABLE_8_ID) - .created(Instant.now()) - .internalName(TABLE_8_INTERNAL_NAME) - .description(TABLE_8_DESCRIPTION) - .name(TABLE_8_NAME) - .tdbid(DATABASE_1_ID) - .queueName(TABLE_8_QUEUE_NAME) - .routingKey(TABLE_8_ROUTING_KEY) - .columns(List.of(TableColumn.builder() - .id(1L) - .ordinalPosition(0) - .cdbid(DATABASE_3_ID) - .tid(TABLE_8_ID) - .name("ID") - .internalName("id") - .columnType(TableColumnType.NUMBER) - .dfid(null) - .isNullAllowed(false) - .autoGenerated(true) - .isPrimaryKey(true) - .build(), - TableColumn.builder() - .id(2L) - .ordinalPosition(1) - .cdbid(DATABASE_3_ID) - .tid(TABLE_8_ID) - .name("Value") - .internalName("value") - .columnType(TableColumnType.DECIMAL) - .dfid(null) - .isNullAllowed(false) - .autoGenerated(false) - .isPrimaryKey(false) - .build())) - .createdBy(USER_1_ID) - .creator(USER_1) - .created(TABLE_8_CREATED) - .lastModified(TABLE_8_LAST_MODIFIED) - .build(); - public final static TableCsvDto TABLE_8_CSV_DTO = TableCsvDto.builder() .data(new HashMap<>() {{ put("value", "2.1"); }}) .build(); + public final static String COLUMN_CONCEPT_TEMPERATURE_NAME = "temperature"; + public final static String COLUMN_CONCEPT_TEMPERATURE_URI = "https://www.wikidata.org/entity/Q11466"; + public final static Instant COLUMN_CONCEPT_TEMPERATURE_CREATED = Instant.now(); + + public final static TableColumnConcept COLUMN_CONCEPT_TEMPERATURE = TableColumnConcept.builder() + .name(COLUMN_CONCEPT_TEMPERATURE_NAME) + .uri(COLUMN_CONCEPT_TEMPERATURE_URI) + .created(COLUMN_CONCEPT_TEMPERATURE_CREATED) + .build(); + + public final static String COLUMN_UNIT_DEGREES_CELSIUS_NAME = "Degrees Celsius"; + public final static String COLUMN_UNIT_DEGREES_CELSIUS_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius"; + public final static Instant COLUMN_UNIT_DEGREES_CELSIUS_CREATED = Instant.now(); + + public final static TableColumnUnit COLUMN_UNIT_DEGREES_CELSIUS = TableColumnUnit.builder() + .name(COLUMN_UNIT_DEGREES_CELSIUS_NAME) + .uri(COLUMN_UNIT_DEGREES_CELSIUS_URI) + .created(COLUMN_CONCEPT_TEMPERATURE_CREATED) + .build(); + public final static Long COLUMN_1_1_ID = 1L; public final static Integer COLUMN_1_1_ORDINALPOS = 0; public final static Boolean COLUMN_1_1_PRIMARY = true; @@ -1754,6 +1735,28 @@ public abstract class BaseTest { public final static String COLUMN_1_4_CHECK = null; public final static List<String> COLUMN_1_4_ENUM_VALUES = null; + public final static ColumnSemanticsUpdateDto COLUMN_1_4_SEMANTICS_UPDATE_DTO = ColumnSemanticsUpdateDto.builder() + .conceptUri(COLUMN_CONCEPT_TEMPERATURE_URI) + .unitUri(COLUMN_UNIT_DEGREES_CELSIUS_URI) + .build(); + + public final static TableColumn COLUMN_1_4_WITH_SEMANTICS = TableColumn.builder() + .id(COLUMN_1_4_ID) + .ordinalPosition(COLUMN_1_4_ORDINALPOS) + .cdbid(DATABASE_1_ID) + .tid(TABLE_1_ID) + .name(COLUMN_1_4_NAME) + .internalName(COLUMN_1_4_INTERNAL_NAME) + .columnType(COLUMN_1_4_TYPE) + .dfid(COLUMN_1_4_DATE_FORMAT) + .isNullAllowed(COLUMN_1_4_NULL) + .autoGenerated(COLUMN_1_4_AUTO_GENERATED) + .isPrimaryKey(COLUMN_1_4_PRIMARY) + .enumValues(COLUMN_1_4_ENUM_VALUES) + .concept(COLUMN_CONCEPT_TEMPERATURE) + .unit(COLUMN_UNIT_DEGREES_CELSIUS) + .build(); + public final static Long COLUMN_1_5_ID = 5L; public final static Integer COLUMN_1_5_ORDINALPOS = 4; public final static Boolean COLUMN_1_5_PRIMARY = false; @@ -2170,6 +2173,100 @@ public abstract class BaseTest { public final static String COLUMN_5_4_CHECK = null; public final static List<String> COLUMN_5_4_ENUM_VALUES = null; + public final static Long COLUMN_8_1_ID = 26L; + public final static Integer COLUMN_8_1_ORDINALPOS = 0; + public final static Boolean COLUMN_8_1_PRIMARY = true; + public final static String COLUMN_8_1_NAME = "ID"; + public final static String COLUMN_8_1_INTERNAL_NAME = "id"; + public final static TableColumnType COLUMN_8_1_TYPE = TableColumnType.NUMBER; + public final static ColumnTypeDto COLUMN_8_1_TYPE_DTO = ColumnTypeDto.NUMBER; + public final static Long COLUMN_8_1_DATE_FORMAT = null; + public final static Boolean COLUMN_8_1_NULL = false; + public final static Boolean COLUMN_8_1_UNIQUE = true; + public final static Boolean COLUMN_8_1_AUTO_GENERATED = true; + public final static String COLUMN_8_1_FOREIGN_KEY = null; + public final static String COLUMN_8_1_CHECK = null; + public final static List<String> COLUMN_8_1_ENUM_VALUES = null; + + public final static Long COLUMN_8_2_ID = 27L; + public final static Integer COLUMN_8_2_ORDINALPOS = 1; + public final static Boolean COLUMN_8_2_PRIMARY = true; + public final static String COLUMN_8_2_NAME = "ID"; + public final static String COLUMN_8_2_INTERNAL_NAME = "id"; + public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.NUMBER; + public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.NUMBER; + public final static Long COLUMN_8_2_DATE_FORMAT = null; + public final static Boolean COLUMN_8_2_NULL = false; + public final static Boolean COLUMN_8_2_UNIQUE = true; + public final static Boolean COLUMN_8_2_AUTO_GENERATED = true; + public final static String COLUMN_8_2_FOREIGN_KEY = null; + public final static String COLUMN_8_2_CHECK = null; + public final static List<String> COLUMN_8_2_ENUM_VALUES = null; + + public final static ColumnSemanticsUpdateDto COLUMN_8_2_SEMANTICS_UPDATE_DTO = ColumnSemanticsUpdateDto.builder() + .conceptUri(COLUMN_CONCEPT_TEMPERATURE_URI) + .unitUri(COLUMN_UNIT_DEGREES_CELSIUS_URI) + .build(); + + public final static TableColumn COLUMN_8_2_WITH_SEMANTICS = TableColumn.builder() + .id(COLUMN_8_2_ID) + .ordinalPosition(COLUMN_8_2_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_8_ID) + .name(COLUMN_8_2_NAME) + .internalName(COLUMN_8_2_INTERNAL_NAME) + .columnType(COLUMN_8_2_TYPE) + .dfid(COLUMN_8_2_DATE_FORMAT) + .isNullAllowed(COLUMN_8_2_NULL) + .autoGenerated(COLUMN_8_2_AUTO_GENERATED) + .isPrimaryKey(COLUMN_8_2_PRIMARY) + .unit(COLUMN_UNIT_DEGREES_CELSIUS) + .concept(COLUMN_CONCEPT_TEMPERATURE) + .build(); + + public final static List<TableColumn> TABLE_8_COLUMNS = List.of(TableColumn.builder() + .id(COLUMN_8_1_ID) + .ordinalPosition(COLUMN_8_1_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_8_ID) + .name(COLUMN_8_1_NAME) + .internalName(COLUMN_8_1_INTERNAL_NAME) + .columnType(COLUMN_8_1_TYPE) + .dfid(COLUMN_8_1_DATE_FORMAT) + .isNullAllowed(COLUMN_8_1_NULL) + .autoGenerated(COLUMN_8_1_AUTO_GENERATED) + .isPrimaryKey(COLUMN_8_1_PRIMARY) + .build(), + TableColumn.builder() + .id(COLUMN_8_2_ID) + .ordinalPosition(COLUMN_8_2_ORDINALPOS) + .cdbid(DATABASE_3_ID) + .tid(TABLE_8_ID) + .name(COLUMN_8_2_NAME) + .internalName(COLUMN_8_2_INTERNAL_NAME) + .columnType(COLUMN_8_2_TYPE) + .dfid(COLUMN_8_2_DATE_FORMAT) + .isNullAllowed(COLUMN_8_2_NULL) + .autoGenerated(COLUMN_8_2_AUTO_GENERATED) + .isPrimaryKey(COLUMN_8_2_PRIMARY) + .build()); + + public final static Table TABLE_8 = Table.builder() + .id(TABLE_8_ID) + .created(Instant.now()) + .internalName(TABLE_8_INTERNAL_NAME) + .description(TABLE_8_DESCRIPTION) + .name(TABLE_8_NAME) + .tdbid(DATABASE_1_ID) + .queueName(TABLE_8_QUEUE_NAME) + .routingKey(TABLE_8_ROUTING_KEY) + .columns(TABLE_8_COLUMNS) + .createdBy(USER_1_ID) + .creator(USER_1) + .created(TABLE_8_CREATED) + .lastModified(TABLE_8_LAST_MODIFIED) + .build(); + public final static List<String> CONSTRAINTS_1_UNIQUE_1 = List.of(COLUMN_1_1_NAME); public final static List<String> CONSTRAINTS_2_UNIQUE_1 = List.of(COLUMN_2_1_NAME); public final static List<String> CONSTRAINTS_3_UNIQUE_1 = List.of("id"); diff --git a/dbrepo-table-service/pom.xml b/dbrepo-table-service/pom.xml index 60355319f10bdcb9745738a4fe41354c95b96ad0..46fde5c0506ed540b8ebaa6eb9c2d9529d55b0d0 100644 --- a/dbrepo-table-service/pom.xml +++ b/dbrepo-table-service/pom.xml @@ -233,7 +233,9 @@ <exclude>at/tuwien/mapper/**/*</exclude> <exclude>at/tuwien/exception/**/*</exclude> <exclude>at/tuwien/config/**/*</exclude> - <exclude>**/DbrepoContainerManagingApplication.class</exclude> + <exclude>at/tuwien/auth/**/*</exclude> + <exclude>at/tuwien/handlers/**/*</exclude> + <exclude>**/DbrepoTableServiceApplication.class</exclude> </excludes> </configuration> <executions> diff --git a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java deleted file mode 100644 index 412ca4a947e10b2ba1f6a91b6362aeb437fdaacb..0000000000000000000000000000000000000000 --- a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ /dev/null @@ -1,80 +0,0 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.exception.AccessDeniedException; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.mapper.DatabaseMapper; -import at.tuwien.service.AccessService; -import at.tuwien.service.DatabaseService; -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.headers.Header; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.security.Principal; - -@Log4j2 -@CrossOrigin(origins = "*") -@RestController -@RequestMapping("/api/container/{id}/database/{databaseId}/table/{tableId}/access") -public class AccessEndpoint { - - private final AccessService accessService; - private final DatabaseMapper databaseMapper; - - @Autowired - public AccessEndpoint(DatabaseService databaseService, AccessService accessService, DatabaseMapper databaseMapper) { - this.accessService = accessService; - this.databaseMapper = databaseMapper; - } - - @GetMapping - @Transactional - @Timed(value = "access.check", description = "Time needed to check access to a table") - @PreAuthorize("hasAuthority('check-access')") - @Operation(summary = "Check access to some table", security = @SecurityRequirement(name = "bearerAuth")) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", - description = "Check access successfully", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = DatabaseAccessDto.class))}), - @ApiResponse(responseCode = "403", - description = "Access to the database is forbidden", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "405", - description = "Check access not permitted", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - }) - public ResponseEntity<DatabaseAccessDto> checkAccess(@NotBlank @PathVariable("id") Long containerId, - @NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @NotNull Principal principal) - throws AccessDeniedException { - log.debug("endpoint check access to database, containerId={}, databaseId={}, principal={}", - containerId, databaseId, principal); - final DatabaseAccess access = accessService.hasAccess(databaseId, tableId, principal.getName()); - final DatabaseAccessDto dto = databaseMapper.databaseAccessToDatabaseAccessDto(access); - log.trace("check access resulted in dto {}", dto); - return ResponseEntity.ok(dto); - } - -} diff --git a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java b/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java index 24fe7d9b93e029ec46bae35d1aa05f6d543714b8..73df4fddb494a6f8b885c02c356798a1fe682220 100644 --- a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java +++ b/dbrepo-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java @@ -1,6 +1,5 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.DatabaseAccessDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.api.error.ApiErrorDto; @@ -8,6 +7,7 @@ import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; import at.tuwien.mapper.TableMapper; import at.tuwien.service.TableService; +import at.tuwien.validation.EndpointValidator; import io.micrometer.core.annotation.Timed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -34,11 +34,13 @@ public class TableColumnEndpoint { private final TableMapper tableMapper; private final TableService tableService; + private final EndpointValidator endpointValidator; @Autowired - public TableColumnEndpoint(TableMapper tableMapper, TableService tableService) { + public TableColumnEndpoint(TableMapper tableMapper, TableService tableService, EndpointValidator endpointValidator) { this.tableMapper = tableMapper; this.tableService = tableService; + this.endpointValidator = endpointValidator; } @PutMapping @@ -78,11 +80,13 @@ public class TableColumnEndpoint { @NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("columnId") Long columnId, @NotNull @Valid @RequestBody ColumnSemanticsUpdateDto updateDto, - @NotNull Principal principal) throws NotAllowedException, + @NotNull Principal principal) throws TableNotFoundException, TableMalformedException, DatabaseNotFoundException, - ContainerNotFoundException, UnitNotFoundException, ConceptNotFoundException { + ContainerNotFoundException, UnitNotFoundException, ConceptNotFoundException, NotAllowedException { log.debug("endpoint update table, containerId={}, databaseId={}, tableId={}, principal={}", containerId, databaseId, tableId, principal); + endpointValidator.validateOnlyAccess(containerId, databaseId, principal, true); + endpointValidator.validateOnlyOwnerOrWriteAll(containerId, databaseId, tableId, principal); final TableColumn column = tableService.update(containerId, databaseId, tableId, columnId, updateDto, principal); log.info("Updated table semantics of table with id {} and database with id {}", tableId, databaseId); final ColumnDto dto = tableMapper.tableColumnToColumnDto(column); diff --git a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-table-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index 79326ff8a9267f781a92d7f7176a3e1d03eac28e..006f3b30a740aca837a50e657258848b83a1a6dc 100644 --- a/dbrepo-table-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-table-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -3,11 +3,15 @@ package at.tuwien.validation; import at.tuwien.entities.database.AccessType; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; +import at.tuwien.entities.database.table.Table; import at.tuwien.entities.user.User; +import at.tuwien.exception.ContainerNotFoundException; import at.tuwien.exception.DatabaseNotFoundException; import at.tuwien.exception.NotAllowedException; +import at.tuwien.exception.TableNotFoundException; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; +import at.tuwien.service.TableService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -20,15 +24,13 @@ public class EndpointValidator { private final AccessService accessService; private final DatabaseService databaseService; + private final TableService tableService; @Autowired - public EndpointValidator(AccessService accessService, DatabaseService databaseService) { + public EndpointValidator(AccessService accessService, DatabaseService databaseService, TableService tableService) { this.accessService = accessService; this.databaseService = databaseService; - } - - public void validateOnlyAccess(Long containerId, Long databaseId, Principal principal) throws NotAllowedException, DatabaseNotFoundException { - validateOnlyAccess(containerId, databaseId, principal, false); + this.tableService = tableService; } public void validateOnlyPrivateAccess(Long containerId, Long databaseId, Principal principal, boolean writeAccessOnly) throws NotAllowedException, DatabaseNotFoundException { @@ -45,34 +47,45 @@ public class EndpointValidator { } public void validateOnlyAccess(Long containerId, Long databaseId, Principal principal, boolean writeAccessOnly) throws NotAllowedException, DatabaseNotFoundException { - final Database database = databaseService.find(containerId, databaseId); if (principal == null) { log.error("Access not allowed: database with id {} is not public and no authorization provided", databaseId); throw new NotAllowedException("Access not allowed: database with id " + databaseId + " is not public and no authorization provided"); } - log.trace("principal is {}", principal); + databaseService.find(containerId, databaseId); + log.trace("principal: {}", principal.getName()); final DatabaseAccess access = accessService.find(databaseId, principal.getName()); - log.trace("found access {}", access); + log.trace("found access: {}", access); if (writeAccessOnly && !(access.getType().equals(AccessType.WRITE_OWN) || access.getType().equals(AccessType.WRITE_ALL))) { log.error("Access not allowed: no write access"); throw new NotAllowedException("Access not allowed: no write access"); } } - public void validateOnlyOwner(Long containerId, Long databaseId, Principal principal) - throws DatabaseNotFoundException, NotAllowedException { - final Database database = databaseService.find(containerId, databaseId); + public void validateOnlyOwnerOrWriteAll(Long containerId, Long databaseId, Long tableId, Principal principal) + throws DatabaseNotFoundException, NotAllowedException, TableNotFoundException, ContainerNotFoundException { if (principal == null) { log.error("Access not allowed: no authorization provided"); throw new NotAllowedException("Access not allowed: no authorization provided"); } - log.trace("principal is {}", principal); + final Table table = tableService.findById(containerId, databaseId, tableId); + log.trace("principal: {}", principal.getName()); + log.trace("table creator: {}", table.getCreator().getUsername()); final DatabaseAccess access = accessService.find(databaseId, principal.getName()); log.trace("found access {}", access); - if (!database.getOwner().equals(principal)) { - log.error("Access not allowed: not the owner of this database with id {}", databaseId); - throw new NotAllowedException("Access not allowed: not the owner of this database"); + if (access.getType().equals(AccessType.READ)) { + log.error("Access not allowed: insufficient access (only read-access)"); + throw new NotAllowedException("Access not allowed: insufficient access (only read-access)"); + } + if (table.getCreator().equalsPrincipal(principal) && (access.getType().equals(AccessType.WRITE_OWN) || access.getType().equals(AccessType.WRITE_ALL))) { + log.trace("grant access: table creator with write access"); + return; + } + if (access.getType().equals(AccessType.WRITE_ALL)) { + log.trace("grant access: write-all access"); + return; } + log.error("Access not allowed: insufficient access (neither creator {} nor write-all access)", table.getCreator().getUsername()); + throw new NotAllowedException("Access not allowed: insufficient access (neither creator nor write-all access)"); } public void validateOnlyPrivateHasRole(Long containerId, Long databaseId, Principal principal, String role) @@ -87,7 +100,7 @@ public class EndpointValidator { log.error("Access not allowed: no authorization provided"); throw new NotAllowedException("Access not allowed: no authorization provided"); } - log.trace("principal is {}", principal); + log.trace("principal: {}", principal.getName()); if (!User.hasRole(principal, role)) { log.error("Access not allowed: role {} missing", role); throw new NotAllowedException("Access not allowed: role " + role + " missing"); diff --git a/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableColumnEndpointUnitTest.java b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableColumnEndpointUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d1dd3b32603f7e4ebf80c9eb20b5bf30ad61071c --- /dev/null +++ b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableColumnEndpointUnitTest.java @@ -0,0 +1,286 @@ +package at.tuwien.endpoint; + +import at.tuwien.BaseUnitTest; +import at.tuwien.api.database.table.TableBriefDto; +import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.tuwien.config.IndexConfig; +import at.tuwien.config.ReadyConfig; +import at.tuwien.endpoints.TableColumnEndpoint; +import at.tuwien.endpoints.TableEndpoint; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.DatabaseAccess; +import at.tuwien.entities.database.table.Table; +import at.tuwien.entities.database.table.columns.TableColumn; +import at.tuwien.exception.*; +import at.tuwien.repository.elastic.TableColumnIdxRepository; +import at.tuwien.repository.elastic.TableIdxRepository; +import at.tuwien.service.AccessService; +import at.tuwien.service.ContainerService; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.TableService; +import com.rabbitmq.client.Channel; +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.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +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.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 static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@Log4j2 +@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class) +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class TableColumnEndpointUnitTest extends BaseUnitTest { + + @MockBean + private ReadyConfig readyConfig; + + @MockBean + private Channel channel; + + @MockBean + private IndexConfig indexInitializer; + + @MockBean + private TableIdxRepository tableidxRepository; + + @MockBean + private TableColumnIdxRepository tableColumnidxRepository; + + @MockBean + private AccessService accessService; + + @MockBean + private DatabaseService databaseService; + + @MockBean + private TableService tableService; + + @Autowired + private TableColumnEndpoint tableColumnEndpoint; + + @Test + @WithAnonymousUser + public void update_publicAnonymous_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, null, null, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicHasRoleNoAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicHasRoleHasOnlyReadAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_3_RESEARCHER_READ_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicHasRoleHasOwnWriteAccess_succeeds() throws TableNotFoundException, NotAllowedException, TableMalformedException, UnitNotFoundException, DatabaseNotFoundException, ConceptNotFoundException, ContainerNotFoundException { + + /* test */ + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, COLUMN_8_2_WITH_SEMANTICS, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_3_RESEARCHER_WRITE_OWN_ACCESS); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicHasRoleForeignHasOwnWriteAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_3_DEVELOPER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicDatabaseNotFound_fails() { + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, null, TABLE_8, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_3_RESEARCHER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicTableNotFound_fails() { + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, null, null, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_3_RESEARCHER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_publicHasRoleForeignHasAllWriteAccess_succeeds() throws TableNotFoundException, + NotAllowedException, TableMalformedException, UnitNotFoundException, DatabaseNotFoundException, + ConceptNotFoundException, ContainerNotFoundException { + + /* test */ + generic_update(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, COLUMN_1_1_ID, DATABASE_3, TABLE_8, COLUMN_8_2_WITH_SEMANTICS, COLUMN_8_2_SEMANTICS_UPDATE_DTO, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_3_DEVELOPER_WRITE_ALL_ACCESS); + } + + /* ################################################################################################### */ + /* ## PRIVATE DATABASES ## */ + /* ################################################################################################### */ + + @Test + @WithAnonymousUser + public void update_privateAnonymous_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, null, null, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateHasRoleNoAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateHasRoleHasOnlyReadAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_RESEARCHER_READ_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateHasRoleHasOwnWriteAccess_succeeds() throws TableNotFoundException, NotAllowedException, TableMalformedException, UnitNotFoundException, DatabaseNotFoundException, ConceptNotFoundException, ContainerNotFoundException { + + /* test */ + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, COLUMN_1_4_WITH_SEMANTICS, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateHasRoleForeignHasOwnWriteAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_DEVELOPER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateDatabaseNotFound_fails() { + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, null, TABLE_1, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateTableNotFound_fails() { + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, null, null, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + public void update_privateHasRoleForeignHasAllWriteAccess_succeeds() throws TableNotFoundException, + NotAllowedException, TableMalformedException, UnitNotFoundException, DatabaseNotFoundException, + ConceptNotFoundException, ContainerNotFoundException { + + /* test */ + generic_update(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID, DATABASE_1, TABLE_1, COLUMN_1_4_WITH_SEMANTICS, COLUMN_1_4_SEMANTICS_UPDATE_DTO, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_DEVELOPER_WRITE_ALL_ACCESS); + } + + /* ################################################################################################### */ + /* ## GENERIC TEST CASES ## */ + /* ################################################################################################### */ + + protected ResponseEntity<ColumnDto> generic_update(Long containerId, Long databaseId, Long tableId, Long columnId, + Database database, Table table, TableColumn column, + ColumnSemanticsUpdateDto data, String username, + Principal principal, DatabaseAccess access) + throws DatabaseNotFoundException, NotAllowedException, TableNotFoundException, TableMalformedException, + UnitNotFoundException, ConceptNotFoundException, ContainerNotFoundException { + + /* mock */ + if (database != null) { + when(databaseService.find(containerId, databaseId)) + .thenReturn(database); + } else { + doThrow(DatabaseNotFoundException.class) + .when(databaseService) + .find(containerId, databaseId); + } + if (table != null) { + when(tableService.findById(containerId, databaseId, tableId)) + .thenReturn(table); + when(tableService.update(containerId, databaseId, tableId, columnId, data, principal)) + .thenReturn(column); + } else { + doThrow(TableNotFoundException.class) + .when(tableService) + .update(containerId, databaseId, tableId, columnId, data, principal); + doThrow(TableNotFoundException.class) + .when(tableService) + .findById(containerId, databaseId, tableId); + } + if (access != null) { + when(accessService.find(containerId, username)) + .thenReturn(access); + } else { + doThrow(NotAllowedException.class) + .when(accessService) + .find(containerId, username); + } + + /* test */ + return tableColumnEndpoint.update(containerId, databaseId, tableId, columnId, data, principal); + } +} diff --git a/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointIntegrationTest.java b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..40f8b173051ab18a42ce9b516adb4799cd4fe9aa --- /dev/null +++ b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointIntegrationTest.java @@ -0,0 +1,113 @@ +package at.tuwien.endpoint; + +import at.tuwien.BaseUnitTest; +import at.tuwien.config.DockerConfig; +import at.tuwien.config.H2Utils; +import at.tuwien.config.IndexConfig; +import at.tuwien.config.ReadyConfig; +import at.tuwien.endpoints.TableColumnEndpoint; +import at.tuwien.endpoints.TableEndpoint; +import at.tuwien.exception.*; +import at.tuwien.repository.elastic.TableColumnIdxRepository; +import at.tuwien.repository.elastic.TableIdxRepository; +import at.tuwien.repository.jpa.*; +import at.tuwien.service.AccessService; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.TableService; +import com.rabbitmq.client.Channel; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.AfterEach; +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.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doThrow; + +@Log4j2 +@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class) +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class TableEndpointIntegrationTest extends BaseUnitTest { + + @MockBean + private ReadyConfig readyConfig; + + @MockBean + private Channel channel; + + @MockBean + private IndexConfig indexInitializer; + + @MockBean + private TableIdxRepository tableidxRepository; + + @MockBean + private TableColumnIdxRepository tableColumnidxRepository; + + @Autowired + private ImageRepository imageRepository; + + @Autowired + private ContainerRepository containerRepository; + + @Autowired + private DatabaseRepository databaseRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RealmRepository realmRepository; + + @Autowired + private DatabaseAccessRepository accessRepository; + + @Autowired + private TableEndpoint tableEndpoint; + + @Autowired + private H2Utils h2Utils; + + @BeforeEach + public void beforeEach() { + afterEach(); + /* create network */ + DockerConfig.createAllNetworks(); + /* metadata database */ + h2Utils.runScript("schema.sql"); + imageRepository.save(IMAGE_1); + realmRepository.save(REALM_DBREPO); + userRepository.save(USER_1_SIMPLE); + containerRepository.save(CONTAINER_1_SIMPLE); + databaseRepository.save(DATABASE_1_SIMPLE); + } + + @AfterEach + public void afterEach() { + DockerConfig.removeAllContainers(); + DockerConfig.removeAllNetworks(); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"create-table"}) + public void create_hasRoleHasAccess_succeeds() throws UserNotFoundException, TableMalformedException, NotAllowedException, + QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, AmqpException, + TableNameExistsException, ContainerNotFoundException, InterruptedException { + + /* mock */ + DockerConfig.createContainer(null, CONTAINER_1, CONTAINER_1_ENV); + DockerConfig.startContainer(CONTAINER_1); + accessRepository.save(DATABASE_1_RESEARCHER_WRITE_OWN_ACCESS); + + /* test */ + tableEndpoint.create(CONTAINER_1_ID, DATABASE_1_ID, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL); + } +} diff --git a/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java index 220a6fa3ff4de9195abdec860fa8c35426a710ba..f99b308dd262ebfbac3a4a97f2fee56c2a757199 100644 --- a/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java +++ b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java @@ -13,7 +13,6 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; import at.tuwien.repository.elastic.TableColumnIdxRepository; import at.tuwien.repository.elastic.TableIdxRepository; -import at.tuwien.repository.jpa.*; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; import at.tuwien.service.TableService; @@ -38,7 +37,6 @@ import java.security.Principal; import java.util.List; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @Log4j2 @@ -259,8 +257,8 @@ public class TableEndpointUnitTest extends BaseUnitTest { public void delete_publicNoRole_fails() { /* test */ - assertThrows(NotAllowedException.class, () -> { - generic_findById(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, DATABASE_3, TABLE_8, USER_4_USERNAME, USER_4_PRINCIPAL, null); + assertThrows(AccessDeniedException.class, () -> { + generic_delete(CONTAINER_3_ID, DATABASE_3_ID, TABLE_8_ID, DATABASE_3, TABLE_8, USER_4_PRINCIPAL); }); } @@ -466,7 +464,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { protected ResponseEntity<List<TableBriefDto>> generic_list(Long containerId, Long databaseId, Database database, String username, Principal principal, DatabaseAccess access) throws DatabaseNotFoundException, NotAllowedException { - /* when */ + /* mock */ if (database != null) { when(databaseService.find(containerId, databaseId)) .thenReturn(database); @@ -496,7 +494,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { protected ResponseEntity<TableBriefDto> generic_create(Long containerId, Long databaseId, Database database, TableCreateDto data, String username, Principal principal, DatabaseAccess access) throws DatabaseNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, AmqpException, TableNameExistsException, ContainerNotFoundException { - /* when */ + /* mock */ if (database != null) { when(databaseService.find(containerId, databaseId)) .thenReturn(database); @@ -525,7 +523,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { protected ResponseEntity<TableDto> generic_findById(Long containerId, Long databaseId, Long tableId, Database database, Table table, String username, Principal principal, DatabaseAccess access) throws DatabaseNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, AmqpException, TableNameExistsException, ContainerNotFoundException, TableNotFoundException { - /* when */ + /* mock */ if (table != null) { when(tableService.findById(containerId, databaseId, tableId)) .thenReturn(table); @@ -561,7 +559,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { protected ResponseEntity<?> generic_delete(Long containerId, Long databaseId, Long tableId, Database database, Table table, Principal principal) throws DatabaseNotFoundException, NotAllowedException, ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, DataProcessingException { - /* when */ + /* mock */ if (table != null) { doNothing() .when(tableService) diff --git a/dbrepo-table-service/rest-service/src/test/java/at/tuwien/gateway/QueryServiceGatewayUnitTest.java b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/gateway/QueryServiceGatewayUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c84163790cc840f4ac929c175cd5846f6d88ee65 --- /dev/null +++ b/dbrepo-table-service/rest-service/src/test/java/at/tuwien/gateway/QueryServiceGatewayUnitTest.java @@ -0,0 +1,85 @@ +package at.tuwien.gateway; + +import at.tuwien.BaseUnitTest; +import at.tuwien.config.IndexConfig; +import at.tuwien.config.ReadyConfig; +import at.tuwien.exception.AmqpException; +import at.tuwien.repository.elastic.TableColumnIdxRepository; +import at.tuwien.repository.elastic.TableIdxRepository; +import com.rabbitmq.client.Channel; +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.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@Log4j2 +@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class) +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class QueryServiceGatewayUnitTest extends BaseUnitTest { + + @MockBean + private ReadyConfig readyConfig; + + @MockBean + private Channel channel; + + @MockBean + private IndexConfig indexInitializer; + + @MockBean + private TableIdxRepository tableidxRepository; + + @MockBean + private TableColumnIdxRepository tableColumnidxRepository; + + @MockBean + private RestTemplate restTemplate; + + @Autowired + private QueryServiceGateway queryServiceGateway; + + @Test + public void declareConsumer_succeeds() throws AmqpException { + final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.ACCEPTED) + .build(); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class))) + .thenReturn(mock); + + /* test */ + queryServiceGateway.declareConsumer(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, "abc"); + } + + @Test + public void declareConsumer_fails() { + final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.NO_CONTENT) + .build(); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class))) + .thenReturn(mock); + + /* test */ + assertThrows(AmqpException.class, () -> { + queryServiceGateway.declareConsumer(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, "abc"); + }); + } + +} diff --git a/dbrepo-table-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-table-service/services/src/main/java/at/tuwien/service/AccessService.java index efe2e564b81eb845098c09d481028a55aaf750f0..e09173e665459818c8e5885c7f9296f8ced6d517 100644 --- a/dbrepo-table-service/services/src/main/java/at/tuwien/service/AccessService.java +++ b/dbrepo-table-service/services/src/main/java/at/tuwien/service/AccessService.java @@ -11,13 +11,12 @@ public interface AccessService { DatabaseAccess find(Long databaseId, String username) throws NotAllowedException; /** - * Checks if the user with username has access to the table with given id in database with given id. + * Checks if the user with username has access to the database with given id. * - * @param databaseId The database id. - * @param tableId The table id. - * @param username The username. + * @param databaseId The database id. + * @param username The username. * @return The access object. * @throws AccessDeniedException The user does not have access. */ - DatabaseAccess hasAccess(Long databaseId, Long tableId, String username) throws AccessDeniedException; + DatabaseAccess hasAccess(Long databaseId, String username) throws AccessDeniedException; } diff --git a/dbrepo-table-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-table-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java index 1a2f71eab8f384919c4cd22fa43526ac4c8d630f..91d4f41a8a4078d50971f24139efa933b73cd508 100644 --- a/dbrepo-table-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java +++ b/dbrepo-table-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java @@ -36,7 +36,7 @@ public class AccessServiceImpl implements AccessService { @Override @Transactional(readOnly = true) - public DatabaseAccess hasAccess(Long databaseId, Long tableId, String username) throws AccessDeniedException { + public DatabaseAccess hasAccess(Long databaseId, String username) throws AccessDeniedException { final Optional<DatabaseAccess> optional = databaseAccessRepository.findByDatabaseIdAndUsername(databaseId, username); if (optional.isEmpty()) { log.error("Failed to retrieve access, not found");