Skip to content
Snippets Groups Projects
Unverified Commit b0e03e01 authored by Martin Weise's avatar Martin Weise
Browse files

Fixed user permissions

parent 89f1b5de
No related branches found
No related tags found
2 merge requests!81New stable release,!71Wrong interface, now creator interface, removed the persist method as it does...
This commit is part of merge request !81. Comments created here will be created in the context of that merge request.
...@@ -4,6 +4,8 @@ target/ ...@@ -4,6 +4,8 @@ target/
!**/src/main/**/target/ !**/src/main/**/target/
!**/src/test/**/target/ !**/src/test/**/target/
.invenio/
# Environment # Environment
.env .env
......
service_ready
ready
package at.tuwien.endpoint; package at.tuwien.endpoint;
import at.tuwien.api.user.UserDetailsDto;
import at.tuwien.entities.database.Database; import at.tuwien.entities.database.Database;
import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.Table;
import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.Identifier;
import at.tuwien.exception.DatabaseNotFoundException; import at.tuwien.exception.DatabaseNotFoundException;
import at.tuwien.exception.IdentifierNotFoundException; import at.tuwien.exception.IdentifierNotFoundException;
import at.tuwien.exception.TableNotFoundException; import at.tuwien.exception.TableNotFoundException;
import at.tuwien.querystore.Query;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.IdentifierService; import at.tuwien.service.IdentifierService;
import at.tuwien.service.QueryService;
import at.tuwien.service.TableService; import at.tuwien.service.TableService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
...@@ -45,6 +44,9 @@ public abstract class AbstractEndpoint { ...@@ -45,6 +44,9 @@ public abstract class AbstractEndpoint {
log.error("Failed to find table with id {}", tableId); log.error("Failed to find table with id {}", tableId);
return false; return false;
} }
if (principal != null && table.getDatabase().getCreator().getUsername().equals(principal.getName())) {
return true;
}
/* view-only operations are allowed on public databases */ /* view-only operations are allowed on public databases */
if (table.getDatabase().getIsPublic() && List.of("DATA_EXPORT", "DATA_VIEW").contains(permissionCode)) { if (table.getDatabase().getIsPublic() && List.of("DATA_EXPORT", "DATA_VIEW").contains(permissionCode)) {
return true; return true;
...@@ -70,14 +72,18 @@ public abstract class AbstractEndpoint { ...@@ -70,14 +72,18 @@ public abstract class AbstractEndpoint {
log.error("Failed to find database with id {}", databaseId); log.error("Failed to find database with id {}", databaseId);
return false; return false;
} }
if (!database.getIsPublic() && !hasPublicIdentifier(queryId, principal)) { if (hasPublicIdentifier(queryId)) {
return false; return true;
}
/* modification operations are limited to the creator */
if (isMyPrivateIdentifier(queryId, principal)) {
return true;
} }
/* view-only operations are allowed on public databases */ /* view-only operations are allowed on public databases */
if (List.of("QUERY_VIEW_ALL", "QUERY_VIEW", "QUERY_EXPORT").contains(permissionCode)) { if (database.getIsPublic() && List.of("QUERY_VIEW_ALL", "QUERY_VIEW", "QUERY_EXPORT").contains(
permissionCode)) {
return true; return true;
} }
/* modification operations are limited to the creator */
if (principal == null) { if (principal == null) {
return false; return false;
} }
...@@ -91,14 +97,7 @@ public abstract class AbstractEndpoint { ...@@ -91,14 +97,7 @@ public abstract class AbstractEndpoint {
return database.getCreator().getUsername().equals(principal.getName()); return database.getCreator().getUsername().equals(principal.getName());
} }
/** protected Boolean hasPublicIdentifier(Long queryId) {
* Determines if an identifier exists for a query with id and if the principal user is allowed to see it
*
* @param queryId The query id.
* @param principal The principal.
* @return True if the query result set can be viewed, false otherwise.
*/
protected Boolean hasPublicIdentifier(Long queryId, Principal principal) {
final Identifier identifier; final Identifier identifier;
try { try {
identifier = identifierService.findByQueryId(queryId); identifier = identifierService.findByQueryId(queryId);
...@@ -107,12 +106,35 @@ public abstract class AbstractEndpoint { ...@@ -107,12 +106,35 @@ public abstract class AbstractEndpoint {
return false; return false;
} }
if (identifier.getVisibility().equals(EVERYONE)) { if (identifier.getVisibility().equals(EVERYONE)) {
log.debug("query {} has public identifier", queryId);
return true;
}
log.debug("query {} does not have a public identifier", queryId);
return false;
}
protected Boolean isMyPrivateIdentifier(Long queryId, Principal principal) {
final Identifier identifier;
try {
identifier = identifierService.findByQueryId(queryId);
} catch (IdentifierNotFoundException e) {
log.warn("Identifier not found");
return false;
}
if (identifier.getDatabase().getIsPublic()) {
log.debug("query {} is within a public database", queryId);
return true; return true;
} }
if (principal == null) { if (principal == null) {
log.debug("query {} does not have a identifier belonging to me", queryId);
return false; return false;
} }
return identifier.getCreator().getUsername().equals(principal.getName()); if (identifier.getCreator().getUsername().equals(principal.getName())) {
log.debug("query {} has identifier belonging to {}", queryId, principal.getName());
return true;
}
log.debug("query {} does not have an identifier belonging to {}", queryId, principal.getName());
return false;
} }
} }
...@@ -39,8 +39,7 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -39,8 +39,7 @@ public class QueryEndpoint extends AbstractEndpoint {
} }
@PutMapping @PutMapping
@Transactional @Transactional(readOnly = true)
@PreAuthorize("hasPermission(#databaseId, 'QUERY_EXECUTE')")
@Operation(summary = "Execute query", security = @SecurityRequirement(name = "bearerAuth")) @Operation(summary = "Execute query", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<QueryResultDto> execute(@NotNull @PathVariable("id") Long id, public ResponseEntity<QueryResultDto> execute(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
...@@ -52,7 +51,9 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -52,7 +51,9 @@ public class QueryEndpoint extends AbstractEndpoint {
ContainerNotFoundException, ColumnParseException, UserNotFoundException, TableMalformedException, ContainerNotFoundException, ColumnParseException, UserNotFoundException, TableMalformedException,
NotAllowedException { NotAllowedException {
if (!hasDatabasePermission(databaseId, databaseId, "QUERY_EXECUTE", principal)) { if (!hasDatabasePermission(databaseId, databaseId, "QUERY_EXECUTE", principal)) {
throw new NotAllowedException("Query execution not allowed"); log.error("Missing execute query permission");
log.debug("missing permission to {}", "QUERY_EXECUTE");
throw new NotAllowedException("Missing execute query permission");
} }
/* validation */ /* validation */
if (data.getStatement() == null || data.getStatement().isBlank()) { if (data.getStatement() == null || data.getStatement().isBlank()) {
...@@ -66,9 +67,8 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -66,9 +67,8 @@ public class QueryEndpoint extends AbstractEndpoint {
} }
@PutMapping("/{queryId}") @PutMapping("/{queryId}")
@Transactional @Transactional(readOnly = true)
@PreAuthorize("hasPermission(#databaseId, 'QUERY_RE_EXECUTE')") @Operation(summary = "Re-execute some query")
@Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long id, public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("queryId") Long queryId, @NotNull @PathVariable("queryId") Long queryId,
...@@ -79,7 +79,9 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -79,7 +79,9 @@ public class QueryEndpoint extends AbstractEndpoint {
TableNotFoundException, QueryMalformedException, ContainerNotFoundException, TableMalformedException, TableNotFoundException, QueryMalformedException, ContainerNotFoundException, TableMalformedException,
ColumnParseException, NotAllowedException { ColumnParseException, NotAllowedException {
if (!hasQueryPermission(databaseId, queryId, "QUERY_RE_EXECUTE", principal)) { if (!hasQueryPermission(databaseId, queryId, "QUERY_RE_EXECUTE", principal)) {
throw new NotAllowedException("Query re-execution not allowed"); log.error("Missing re-execute query permission");
log.debug("missing permission to {}", "QUERY_RE_EXECUTE");
throw new NotAllowedException("Missing re-execute query permission");
} }
final Query query = storeService.findOne(id, databaseId, queryId); final Query query = storeService.findOne(id, databaseId, queryId);
final QueryResultDto result = queryService.reExecute(id, databaseId, query, page, size); final QueryResultDto result = queryService.reExecute(id, databaseId, query, page, size);
...@@ -99,7 +101,9 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -99,7 +101,9 @@ public class QueryEndpoint extends AbstractEndpoint {
throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
ContainerNotFoundException, TableMalformedException, FileStorageException, NotAllowedException { ContainerNotFoundException, TableMalformedException, FileStorageException, NotAllowedException {
if (!hasQueryPermission(databaseId, queryId, "QUERY_EXPORT", principal)) { if (!hasQueryPermission(databaseId, queryId, "QUERY_EXPORT", principal)) {
throw new NotAllowedException("Query export not allowed"); log.error("Missing execute query permission");
log.debug("missing permission to {}", "QUERY_EXPORT");
throw new NotAllowedException("Missing execute query permission");
} }
storeService.findOne(id, databaseId, queryId); storeService.findOne(id, databaseId, queryId);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
......
...@@ -8,6 +8,7 @@ import at.tuwien.exception.*; ...@@ -8,6 +8,7 @@ import at.tuwien.exception.*;
import at.tuwien.mapper.QueryMapper; import at.tuwien.mapper.QueryMapper;
import at.tuwien.service.*; import at.tuwien.service.*;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
...@@ -18,6 +19,7 @@ import javax.validation.constraints.NotNull; ...@@ -18,6 +19,7 @@ import javax.validation.constraints.NotNull;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
@Log4j2
@RestController @RestController
@RequestMapping("/api/container/{id}/database/{databaseId}/query") @RequestMapping("/api/container/{id}/database/{databaseId}/query")
public class StoreEndpoint extends AbstractEndpoint { public class StoreEndpoint extends AbstractEndpoint {
...@@ -48,7 +50,9 @@ public class StoreEndpoint extends AbstractEndpoint { ...@@ -48,7 +50,9 @@ public class StoreEndpoint extends AbstractEndpoint {
throws QueryStoreException, throws QueryStoreException,
DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, NotAllowedException { DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, NotAllowedException {
if (!hasQueryPermission(databaseId, null, "QUERY_VIEW_ALL", principal)) { if (!hasQueryPermission(databaseId, null, "QUERY_VIEW_ALL", principal)) {
throw new NotAllowedException("Query view all not allowed"); log.error("Missing view all queries permission");
log.debug("missing permission to {}", "QUERY_VIEW_ALL");
throw new NotAllowedException("Missing view all queries permission");
} }
final List<Query> queries = storeService.findAll(id, databaseId); final List<Query> queries = storeService.findAll(id, databaseId);
return ResponseEntity.ok(queryMapper.queryListToQueryDtoList(queries)); return ResponseEntity.ok(queryMapper.queryListToQueryDtoList(queries));
...@@ -56,7 +60,6 @@ public class StoreEndpoint extends AbstractEndpoint { ...@@ -56,7 +60,6 @@ public class StoreEndpoint extends AbstractEndpoint {
@GetMapping("/{queryId}") @GetMapping("/{queryId}")
@Transactional(readOnly = true) @Transactional(readOnly = true)
@PreAuthorize("hasPermission(#databaseId, 'QUERY_VIEW')")
@Operation(summary = "Find some query") @Operation(summary = "Find some query")
public ResponseEntity<QueryDto> find(@NotNull @PathVariable("id") Long id, public ResponseEntity<QueryDto> find(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
...@@ -66,7 +69,9 @@ public class StoreEndpoint extends AbstractEndpoint { ...@@ -66,7 +69,9 @@ public class StoreEndpoint extends AbstractEndpoint {
QueryStoreException, QueryNotFoundException, ContainerNotFoundException, UserNotFoundException, QueryStoreException, QueryNotFoundException, ContainerNotFoundException, UserNotFoundException,
NotAllowedException { NotAllowedException {
if (!hasQueryPermission(databaseId, queryId, "QUERY_VIEW", principal)) { if (!hasQueryPermission(databaseId, queryId, "QUERY_VIEW", principal)) {
throw new NotAllowedException("Query view not allowed"); log.error("Missing view query permission");
log.debug("missing permission to {}", "QUERY_VIEW");
throw new NotAllowedException("Missing view query permission");
} }
final Query query = storeService.findOne(id, databaseId, queryId); final Query query = storeService.findOne(id, databaseId, queryId);
final QueryDto dto = queryMapper.queryToQueryDto(query); final QueryDto dto = queryMapper.queryToQueryDto(query);
......
...@@ -67,6 +67,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -67,6 +67,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/* our public endpoints */ /* our public endpoints */
.antMatchers(HttpMethod.GET, "/api/container/**/database/data/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/data/**").permitAll()
.antMatchers(HttpMethod.POST, "/api/container/**/database/**/table/**/data").permitAll() .antMatchers(HttpMethod.POST, "/api/container/**/database/**/table/**/data").permitAll()
.antMatchers(HttpMethod.PUT, "/api/container/**/database/**/query/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/data/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/data/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/export/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/export/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/query/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/query/**").permitAll()
......
...@@ -61,7 +61,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService ...@@ -61,7 +61,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
} }
@Override @Override
@Transactional @Transactional(readOnly = true)
public QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto statement, public QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto statement,
Principal principal, Long page, Long size) Principal principal, Long page, Long size)
throws DatabaseNotFoundException, ImageNotSupportedException, QueryMalformedException, QueryStoreException, throws DatabaseNotFoundException, ImageNotSupportedException, QueryMalformedException, QueryStoreException,
...@@ -73,7 +73,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService ...@@ -73,7 +73,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
} }
@Override @Override
@Transactional @Transactional(readOnly = true)
public QueryResultDto reExecute(Long containerId, Long databaseId, Query query, Long page, Long size) public QueryResultDto reExecute(Long containerId, Long databaseId, Query query, Long page, Long size)
throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException,
ColumnParseException, TableMalformedException { ColumnParseException, TableMalformedException {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment