Skip to content

Commit

Permalink
Fixed Security Exceptions For Requests Wihtout PPL Access (#2033)
Browse files Browse the repository at this point in the history
Signed-off-by: Vamsi Manohar <[email protected]>
(cherry picked from commit 56bc7d5)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Aug 30, 2023
1 parent 2c1212e commit 201f3d6
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
*
* * Copyright OpenSearch Contributors
* * SPDX-License-Identifier: Apache-2.0
*
*/

package org.opensearch.sql.datasources.exceptions;

/**
* This is the base class for all DataSource Client Exceptions. All datasource connector modules
* will extend this exception for their respective connection clients.
*/
public class DataSourceClientException extends RuntimeException {

public DataSourceClientException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.OpenSearchSecurityException;
import org.opensearch.client.node.NodeClient;
import org.opensearch.core.action.ActionListener;
import org.opensearch.core.rest.RestStatus;
Expand All @@ -28,6 +29,7 @@
import org.opensearch.rest.RestRequest;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.common.setting.Settings;
import org.opensearch.sql.datasources.exceptions.DataSourceClientException;
import org.opensearch.sql.exception.ExpressionEvaluationException;
import org.opensearch.sql.exception.QueryEngineException;
import org.opensearch.sql.exception.SemanticCheckException;
Expand Down Expand Up @@ -67,7 +69,9 @@ private static boolean isClientError(Exception e) {
|| e instanceof SemanticCheckException
|| e instanceof ExpressionEvaluationException
|| e instanceof QueryEngineException
|| e instanceof SyntaxCheckException;
|| e instanceof SyntaxCheckException
|| e instanceof DataSourceClientException
|| e instanceof IllegalAccessException;
}

@Override
Expand Down Expand Up @@ -132,8 +136,9 @@ public void onFailure(Exception e) {
channel,
INTERNAL_SERVER_ERROR,
"Failed to explain the query due to error: " + e.getMessage());
} else if (e instanceof IllegalAccessException) {
reportError(channel, e, BAD_REQUEST);
} else if (e instanceof OpenSearchSecurityException) {
OpenSearchSecurityException exception = (OpenSearchSecurityException) e;
reportError(channel, exception, exception.status());
} else {
LOG.error("Error happened during query handling", e);
if (isClientError(e)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.opensearch.sql.prometheus.exceptions.PrometheusClientException;
import org.opensearch.sql.prometheus.request.system.model.MetricMetadata;

public class PrometheusClientImpl implements PrometheusClient {
Expand Down Expand Up @@ -111,14 +113,21 @@ private List<String> toListOfLabels(JSONArray array) {

private JSONObject readResponse(Response response) throws IOException {
if (response.isSuccessful()) {
JSONObject jsonObject = new JSONObject(Objects.requireNonNull(response.body()).string());
JSONObject jsonObject;
try {
jsonObject = new JSONObject(Objects.requireNonNull(response.body()).string());
} catch (JSONException jsonException) {
throw new PrometheusClientException(
"Prometheus returned unexpected body, "
+ "please verify your prometheus server setup.");
}
if ("success".equals(jsonObject.getString("status"))) {
return jsonObject;
} else {
throw new RuntimeException(jsonObject.getString("error"));
throw new PrometheusClientException(jsonObject.getString("error"));
}
} else {
throw new RuntimeException(
throw new PrometheusClientException(
String.format(
"Request to Prometheus is Unsuccessful with : %s",
Objects.requireNonNull(response.body(), "Response body can't be null").string()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
*
* * Copyright OpenSearch Contributors
* * SPDX-License-Identifier: Apache-2.0
*
*/

package org.opensearch.sql.prometheus.exceptions;

import org.opensearch.sql.datasources.exceptions.DataSourceClientException;

/** PrometheusClientException. */
public class PrometheusClientException extends DataSourceClientException {
public PrometheusClientException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.opensearch.sql.data.type.ExprCoreType;
import org.opensearch.sql.data.type.ExprType;
import org.opensearch.sql.prometheus.client.PrometheusClient;
import org.opensearch.sql.prometheus.exceptions.PrometheusClientException;
import org.opensearch.sql.prometheus.storage.PrometheusMetricDefaultSchema;

/**
Expand Down Expand Up @@ -80,7 +81,7 @@ public Map<String, ExprType> getFieldTypes() {
"Error while fetching labels for {} from prometheus: {}",
metricName,
e.getMessage());
throw new RuntimeException(
throw new PrometheusClientException(
String.format(
"Error while fetching labels " + "for %s from prometheus: %s",
metricName, e.getMessage()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ private OkHttpClient getHttpClient(Map<String, String> config) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.callTimeout(1, TimeUnit.MINUTES);
okHttpClient.connectTimeout(30, TimeUnit.SECONDS);
okHttpClient.followRedirects(false);
if (config.get(AUTH_TYPE) != null) {
AuthenticationType authenticationType = AuthenticationType.get(config.get(AUTH_TYPE));
if (AuthenticationType.BASICAUTH.equals(authenticationType)) {
Expand Down Expand Up @@ -162,8 +163,8 @@ private void validateURI(Map<String, String> config) throws URISyntaxException {
if (!matcher.matches()) {
throw new IllegalArgumentException(
String.format(
"Disallowed hostname in the uri: %s. Validate with %s config",
config.get(URI), Settings.Key.DATASOURCES_URI_ALLOWHOSTS.getKeyValue()));
"Disallowed hostname in the uri. Validate with %s config",
Settings.Key.DATASOURCES_URI_ALLOWHOSTS.getKeyValue()));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.sql.prometheus.exceptions.PrometheusClientException;
import org.opensearch.sql.prometheus.request.system.model.MetricMetadata;

@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -73,11 +74,30 @@ void testQueryRangeWith2xxStatusAndError() {
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody(getJson("error_response.json"));
mockWebServer.enqueue(mockResponse);
RuntimeException runtimeException =
PrometheusClientException prometheusClientException =
assertThrows(
RuntimeException.class,
PrometheusClientException.class,
() -> prometheusClient.queryRange(QUERY, STARTTIME, ENDTIME, STEP));
assertEquals("Error", runtimeException.getMessage());
assertEquals("Error", prometheusClientException.getMessage());
RecordedRequest recordedRequest = mockWebServer.takeRequest();
verifyQueryRangeCall(recordedRequest);
}

@Test
@SneakyThrows
void testQueryRangeWithNonJsonResponse() {
MockResponse mockResponse =
new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody(getJson("non_json_response.json"));
mockWebServer.enqueue(mockResponse);
PrometheusClientException prometheusClientException =
assertThrows(
PrometheusClientException.class,
() -> prometheusClient.queryRange(QUERY, STARTTIME, ENDTIME, STEP));
assertEquals(
"Prometheus returned unexpected body, " + "please verify your prometheus server setup.",
prometheusClientException.getMessage());
RecordedRequest recordedRequest = mockWebServer.takeRequest();
verifyQueryRangeCall(recordedRequest);
}
Expand All @@ -90,12 +110,14 @@ void testQueryRangeWithNon2xxError() {
.addHeader("Content-Type", "application/json; charset=utf-8")
.setResponseCode(400);
mockWebServer.enqueue(mockResponse);
RuntimeException runtimeException =
PrometheusClientException prometheusClientException =
assertThrows(
RuntimeException.class,
PrometheusClientException.class,
() -> prometheusClient.queryRange(QUERY, STARTTIME, ENDTIME, STEP));
assertTrue(
runtimeException.getMessage().contains("Request to Prometheus is Unsuccessful with :"));
prometheusClientException
.getMessage()
.contains("Request to Prometheus is Unsuccessful with :"));
RecordedRequest recordedRequest = mockWebServer.takeRequest();
verifyQueryRangeCall(recordedRequest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ void createDataSourceWithHostnameNotMatchingWithAllowHostsConfig() {
exception
.getMessage()
.contains(
"Disallowed hostname in the uri: http://localhost.com:9090. "
"Disallowed hostname in the uri. "
+ "Validate with plugins.query.datasources.uri.allowhosts config"));
}

Expand Down
1 change: 1 addition & 0 deletions prometheus/src/test/resources/non_json_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fadsfadsfasdfasdfadsfasdfadsfadsf

0 comments on commit 201f3d6

Please sign in to comment.