Make sure /v1/query checks access permissions for using filters.
This commit is contained in:
parent
65f706d3cc
commit
3d1c0f8d64
|
@ -139,12 +139,22 @@ public class QueryJSONResolver implements Resolver {
|
|||
}
|
||||
|
||||
private Response getResponse(@Untrusted Request request) {
|
||||
Optional<Response> cachedResult = checkForCachedResult(request);
|
||||
Optional<WebUser> user = request.getUser();
|
||||
boolean canAccessCache = user.map(u -> u.hasPermission(WebPermission.ACCESS_QUERY)).orElse(true);
|
||||
Optional<Response> cachedResult = canAccessCache ? checkForCachedResult(request) : Optional.empty();
|
||||
if (cachedResult.isPresent()) return cachedResult.get();
|
||||
|
||||
InputQueryDto inputQuery = parseInputQuery(request);
|
||||
@Untrusted List<InputFilterDto> queries = inputQuery.getFilters();
|
||||
|
||||
// Check user has permission for the filter if login is enabled.
|
||||
if (user.isPresent()) {
|
||||
Optional<Response> errorResponse = checkFilterPermissions(queries, user.get());
|
||||
if (errorResponse.isPresent()) {
|
||||
return errorResponse.get();
|
||||
}
|
||||
}
|
||||
|
||||
Filter.Result result = filters.apply(queries);
|
||||
List<Filter.ResultPath> resultPath = result.getInverseResultPath();
|
||||
Collections.reverse(resultPath);
|
||||
|
@ -152,6 +162,47 @@ public class QueryJSONResolver implements Resolver {
|
|||
return buildAndStoreResponse(inputQuery, result, resultPath);
|
||||
}
|
||||
|
||||
private Optional<Response> checkFilterPermissions(List<InputFilterDto> queries, WebUser user) {
|
||||
for (InputFilterDto filter : queries) {
|
||||
@Untrusted String filterKind = filter.getKind();
|
||||
if (!isFilterAllowed(user, filterKind)) {
|
||||
return Optional.of(Response.builder()
|
||||
.setStatus(403)
|
||||
.setJSONContent("{\"error\": \"You don't have permission to use one of the given filters\"}")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private boolean isFilterAllowed(WebUser user, @Untrusted String filterKind) {
|
||||
for (WebPermission allowed : getAllowingPermissions(filterKind)) {
|
||||
if (user.hasPermission(allowed)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private WebPermission[] getAllowingPermissions(@Untrusted String filterKind) {
|
||||
switch (filterKind) {
|
||||
case "playedBetween":
|
||||
return new WebPermission[]{
|
||||
WebPermission.ACCESS_QUERY,
|
||||
WebPermission.PAGE_NETWORK_OVERVIEW_GRAPHS_CALENDAR,
|
||||
WebPermission.PAGE_SERVER_ONLINE_ACTIVITY_GRAPHS_CALENDAR
|
||||
};
|
||||
case "geolocations":
|
||||
return new WebPermission[]{
|
||||
WebPermission.ACCESS_QUERY,
|
||||
WebPermission.PAGE_NETWORK_GEOLOCATIONS_MAP,
|
||||
WebPermission.PAGE_SERVER_GEOLOCATIONS_MAP
|
||||
};
|
||||
default:
|
||||
return new WebPermission[]{WebPermission.ACCESS_QUERY};
|
||||
}
|
||||
}
|
||||
|
||||
private InputQueryDto parseInputQuery(@Untrusted Request request) {
|
||||
if (request.getRequestBody().length == 0) {
|
||||
return parseInputQueryFromQueryParams(request);
|
||||
|
|
|
@ -70,6 +70,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||
class AccessControlTest {
|
||||
|
||||
private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
|
||||
private static final String QUERY_VIEW_SIMPLE = "%7B%22afterDate%22%3A%2201%2F01%2F1970%22%2C%22afterTime%22%3A%2200%3A00%22%2C%22beforeDate%22%3A%2201%2F01%2F2024%22%2C%22beforeTime%22%3A%2200%3A00%22%2C%22servers%22%3A%5B%5D%7D";
|
||||
|
||||
private static final HTTPConnector CONNECTOR = new HTTPConnector();
|
||||
|
||||
|
@ -77,6 +78,7 @@ class AccessControlTest {
|
|||
private static String address;
|
||||
private static String cookieNoAccess;
|
||||
|
||||
|
||||
static Stream<Arguments> testCases() {
|
||||
return Stream.of(
|
||||
Arguments.of("/", WebPermission.ACCESS, 302, 403),
|
||||
|
@ -133,6 +135,10 @@ class AccessControlTest {
|
|||
Arguments.of("/v1/filters", WebPermission.ACCESS_QUERY, 200, 403),
|
||||
Arguments.of("/v1/query", WebPermission.ACCESS_QUERY, 400, 403),
|
||||
Arguments.of("/v1/query?q=%5B%5D&view=%7B%22afterDate%22%3A%2224%2F10%2F2022%22%2C%22afterTime%22%3A%2218%3A21%22%2C%22beforeDate%22%3A%2223%2F11%2F2022%22%2C%22beforeTime%22%3A%2217%3A21%22%2C%22servers%22%3A%5B%0A%7B%22serverUUID%22%3A%22" + TestConstants.SERVER_UUID_STRING + "%22%2C%22serverName%22%3A%22" + TestConstants.SERVER_NAME + "%22%2C%22proxy%22%3Afalse%7D%5D%7D", WebPermission.ACCESS_QUERY, 200, 403),
|
||||
Arguments.of("/v1/query?q=%5B%7B%22kind%22%3A%22playedBetween%22%2C%22parameters%22%3A%7B%22afterDate%22%3A%2201%2F01%2F1970%22%2C%22afterTime%22%3A%2200%3A00%22%2C%22beforeDate%22%3A%2201%2F01%2F2024%22%2C%22beforeTime%22%3A%2200%3A00%22%7D%7D%5D&view=" + QUERY_VIEW_SIMPLE, WebPermission.PAGE_NETWORK_OVERVIEW_GRAPHS_CALENDAR, 200, 403),
|
||||
Arguments.of("/v1/query?q=%5B%7B%22kind%22%3A%22playedBetween%22%2C%22parameters%22%3A%7B%22afterDate%22%3A%2201%2F01%2F1970%22%2C%22afterTime%22%3A%2200%3A00%22%2C%22beforeDate%22%3A%2201%2F01%2F2024%22%2C%22beforeTime%22%3A%2200%3A00%22%7D%7D%5D&view=" + QUERY_VIEW_SIMPLE, WebPermission.PAGE_SERVER_ONLINE_ACTIVITY_GRAPHS_CALENDAR, 200, 403),
|
||||
Arguments.of("/v1/query?q=%5B%7B%22kind%22%3A%22geolocations%22%2C%22parameters%22%3A%7B%22selected%22%3A%22%5B%5C%22FIN%5C%22%5D%22%7D%7D%5D&view=" + QUERY_VIEW_SIMPLE, WebPermission.PAGE_NETWORK_GEOLOCATIONS_MAP, 200, 403),
|
||||
Arguments.of("/v1/query?q=%5B%7B%22kind%22%3A%22geolocations%22%2C%22parameters%22%3A%7B%22selected%22%3A%22%5B%5C%22FIN%5C%22%5D%22%7D%7D%5D&view=" + QUERY_VIEW_SIMPLE, WebPermission.PAGE_SERVER_GEOLOCATIONS_MAP, 200, 403),
|
||||
Arguments.of("/v1/errors", WebPermission.ACCESS_ERRORS, 200, 403),
|
||||
Arguments.of("/errors", WebPermission.ACCESS_ERRORS, 200, 403),
|
||||
Arguments.of("/v1/network/listServers", WebPermission.PAGE_NETWORK_PERFORMANCE, 200, 403),
|
||||
|
|
Loading…
Reference in New Issue