[
https://issues.apache.org/jira/browse/KYLIN-5297?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17635798#comment-17635798
]
ASF GitHub Bot commented on KYLIN-5297:
---------------------------------------
github-code-scanning[bot] commented on code in PR #2025:
URL: https://github.com/apache/kylin/pull/2025#discussion_r1026270405
##########
src/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java:
##########
@@ -0,0 +1,634 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.jdbc;
+
+import static org.apache.kylin.jdbc.LoggerUtils.entry;
+import static org.apache.kylin.jdbc.LoggerUtils.exit;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import javax.net.ssl.SSLContext;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.calcite.avatica.ColumnMetaData.ScalarType;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.util.EntityUtils;
+import org.apache.kylin.jdbc.KylinMeta.KMetaCatalog;
+import org.apache.kylin.jdbc.KylinMeta.KMetaColumn;
+import org.apache.kylin.jdbc.KylinMeta.KMetaProject;
+import org.apache.kylin.jdbc.KylinMeta.KMetaSchema;
+import org.apache.kylin.jdbc.KylinMeta.KMetaTable;
+import org.apache.kylin.jdbc.json.GenericResponse;
+import org.apache.kylin.jdbc.json.PreparedQueryRequest;
+import org.apache.kylin.jdbc.json.SQLResponseStub;
+import org.apache.kylin.jdbc.json.StatementParameter;
+import org.apache.kylin.jdbc.json.TableMetaStub;
+import org.apache.kylin.jdbc.json.TableWithComment;
+import org.apache.kylin.jdbc.json.TablesWithCommentResponse;
+import org.apache.kylin.jdbc.json.TableMetaStub.ColumnMetaStub;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class KylinClient implements IRemoteClient {
+
+ // TODO: cannot support tableau
+
+ private static final Logger logger =
LoggerFactory.getLogger(KylinClient.class);
+
+ private final KylinConnection conn;
+ private final Properties connProps;
+ private final CloseableHttpClient httpClient;
+ private final ObjectMapper jsonMapper;
+ private final static int POOL_MAX = 10;
+ private final static int POOL_MIN = 0;
+ private final static int RESPONSE_CODE_200 = 200;
+ private final static int RESPONSE_CODE_201 = 201;
+ private static final String APPLICATION = "application/json";
+ private static final String TIME_ZONE = "UTC";
+
+ public KylinClient(KylinConnection conn) {
+ entry(logger);
+ this.conn = conn;
+ this.connProps = conn.getConnectionProperties();
+ this.httpClient = buildHttpClient();
+ this.jsonMapper = new ObjectMapper();
+ jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ exit(logger);
+ }
+
+ private CloseableHttpClient buildHttpClient() {
+ HttpClientBuilder builder = HttpClients.custom();
+
+ // network timeout
+ int timeout = Integer.parseInt(connProps.getProperty("timeout", "0"));
+ RequestConfig rconf =
RequestConfig.custom().setConnectTimeout(timeout).setSocketTimeout(timeout).build();
+ builder.setDefaultRequestConfig(rconf);
+ logger.debug("use connection timeout " + timeout);
+
+ // SSL friendly
+ PoolingHttpClientConnectionManager cm;
+ if (isSSL()) {
+ try {
+ SSLContext sslContext = SSLContexts.custom()
+ .loadTrustMaterial((TrustStrategy) (x509Certificates,
s) -> true).build();
+ SSLConnectionSocketFactory sslsf = new
SSLConnectionSocketFactory(sslContext, (s, sslSession) -> true);
+ Registry<ConnectionSocketFactory> r =
RegistryBuilder.<ConnectionSocketFactory>create()
+ .register("https", sslsf).build();
+ cm = new PoolingHttpClientConnectionManager(r);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ logger.debug("use SSL connection with optimistic trust");
+ } else {
+ cm = new PoolingHttpClientConnectionManager();
+ logger.debug("use non-SSL connection");
+ }
+
+ // connection pool
+ int pool = Integer.parseInt(connProps.getProperty("pool", "1"));
+ if (pool > POOL_MAX || pool < POOL_MIN) {
+ logger.debug("invalid 'pool', reset to default");
+ pool = 1;
+ }
+ if (pool == 0) {
+ logger.debug("use NO connection pool");
+ } else {
+ cm.setDefaultMaxPerRoute(pool);
+ cm.setMaxTotal(pool);
+ logger.debug("use connection pool size " + pool);
+ }
+
+ builder.setConnectionManager(cm);
+ return builder.build();
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static Class convertType(int sqlType) {
+ Class result = Object.class;
+
+ switch (sqlType) {
+ case Types.CHAR:
+ case Types.VARCHAR:
+ case Types.LONGVARCHAR:
+ result = String.class;
+ break;
+ case Types.NUMERIC:
+ case Types.DECIMAL:
+ result = BigDecimal.class;
+ break;
+ case Types.BIT:
+ case Types.BOOLEAN:
+ result = Boolean.class;
+ break;
+ case Types.TINYINT:
+ result = Byte.class;
+ break;
+ case Types.SMALLINT:
+ result = Short.class;
+ break;
+ case Types.INTEGER:
+ result = Integer.class;
+ break;
+ case Types.BIGINT:
+ result = Long.class;
+ break;
+ case Types.REAL:
+ case Types.FLOAT:
+ case Types.DOUBLE:
+ result = Double.class;
+ break;
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ result = Byte[].class;
+ break;
+ case Types.DATE:
+ result = Date.class;
+ break;
+ case Types.TIME:
+ result = Time.class;
+ break;
+ case Types.TIMESTAMP:
+ result = Timestamp.class;
+ break;
+ default:
+ //do nothing
+ break;
+ }
+
+ return result;
+ }
+
+ public Object wrapObject(String value, int sqlType) {
+ if (null == value) {
+ return null;
+ }
+
+ switch (sqlType) {
+ case Types.CHAR:
+ case Types.VARCHAR:
+ case Types.LONGVARCHAR:
+ return value;
+ case Types.NUMERIC:
+ case Types.DECIMAL:
+ return new BigDecimal(value);
+ case Types.BIT:
+ case Types.BOOLEAN:
+ return Boolean.parseBoolean(value);
+ case Types.TINYINT:
+ return Byte.valueOf(value);
+ case Types.SMALLINT:
+ return Short.valueOf(value);
+ case Types.INTEGER:
+ return Integer.parseInt(value);
+ case Types.BIGINT:
+ return Long.parseLong(value);
+ case Types.FLOAT:
+ return Float.parseFloat(value);
+ case Types.REAL:
+ case Types.DOUBLE:
+ return Double.parseDouble(value);
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ return value.getBytes();
+ case Types.DATE:
+ return dateConverter(value);
+ case Types.TIME:
+ return timeConverter(value);
+ case Types.TIMESTAMP:
+ return timestampConverter(value);
+ default:
+ //do nothing
+ break;
+ }
+
+ return value;
+ }
+
+ private Date dateConverter(String value) {
+ try {
+ return new Date(parseDateTime(value, "yyyy-MM-dd"));
+ } catch (ParseException ex) {
+ logger.error("parse date failed!", ex);
+ return null;
+ }
+ }
+
+ private Time timeConverter(String value) {
+ try {
+ return new Time(parseDateTime(value, "HH:mm:ss"));
+ } catch (ParseException ex) {
+ logger.error("parse time failed!", ex);
+ return null;
+ }
+ }
+
+ private Timestamp timestampConverter(String value) {
+ String[] formats = new String[] {"yyyy-MM-dd HH:mm:ss.SSS",
"yyyy-MM-dd HH:mm:ss"};
+ ParseException ex = null;
+ for (String format:formats) {
+ try {
+ return new Timestamp(parseDateTime(value, format));
+ } catch (ParseException e) {
+ ex = e;
+ }
+ }
+ logger.error("parse timestamp failed!", ex);
+ return null;
+ }
+
+ private long parseDateTime(String value, String format) throws
ParseException {
+ SimpleDateFormat formatter = new SimpleDateFormat(format);
+ formatter.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
+ return formatter.parse(value).getTime();
+ }
+
+ private boolean isSSL() {
+ return Boolean.parseBoolean(connProps.getProperty("ssl", "false"));
+ }
+
+ private String baseUrl() {
+ return (isSSL() ? "https://" : "http://") + conn.getBaseUrl();
+ }
+
+ private void addHttpHeadersV2(HttpRequestBase method) {
+ String headerVal = "application/vnd.apache.kylin-v4-public+json,
text/plain, */*";
+ method.addHeader("Accept", headerVal);
+ addCommonHttpHeaders(method);
+ }
+
+ private void addCommonHttpHeaders(HttpRequestBase method) {
+ method.addHeader("Content-Type", APPLICATION);
+ method.addHeader("User-Agent", "KylinJDBCDriver");
+ String authToken = connProps.getProperty("auth-token");
+ if (authToken == null || authToken.trim().isEmpty()) {
+ String username = connProps.getProperty("user");
+ String password = connProps.getProperty("password");
+ authToken = DatatypeConverter.printBase64Binary((username + ":" +
password).getBytes());
+ }
+ method.addHeader("Authorization", "Basic " + authToken);
Review Comment:
## Basic authentication should not be used
<!--SONAR_ISSUE_KEY:AYSKSzxuqo1OziNXkSc2-->Use a more secure method than
basic authentication. <p>See more on <a
href="https://sonarcloud.io/project/issues?id=apache_kylin&issues=AYSKSzxuqo1OziNXkSc2&open=AYSKSzxuqo1OziNXkSc2&pullRequest=2025">SonarCloud</a></p>
[Show more details](https://github.com/apache/kylin/security/code-scanning/1)
##########
src/jdbc/src/main/java/org/apache/kylin/jdbc/KylinClient.java:
##########
@@ -0,0 +1,634 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.jdbc;
+
+import static org.apache.kylin.jdbc.LoggerUtils.entry;
+import static org.apache.kylin.jdbc.LoggerUtils.exit;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import javax.net.ssl.SSLContext;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.calcite.avatica.ColumnMetaData.ScalarType;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.util.EntityUtils;
+import org.apache.kylin.jdbc.KylinMeta.KMetaCatalog;
+import org.apache.kylin.jdbc.KylinMeta.KMetaColumn;
+import org.apache.kylin.jdbc.KylinMeta.KMetaProject;
+import org.apache.kylin.jdbc.KylinMeta.KMetaSchema;
+import org.apache.kylin.jdbc.KylinMeta.KMetaTable;
+import org.apache.kylin.jdbc.json.GenericResponse;
+import org.apache.kylin.jdbc.json.PreparedQueryRequest;
+import org.apache.kylin.jdbc.json.SQLResponseStub;
+import org.apache.kylin.jdbc.json.StatementParameter;
+import org.apache.kylin.jdbc.json.TableMetaStub;
+import org.apache.kylin.jdbc.json.TableWithComment;
+import org.apache.kylin.jdbc.json.TablesWithCommentResponse;
+import org.apache.kylin.jdbc.json.TableMetaStub.ColumnMetaStub;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class KylinClient implements IRemoteClient {
+
+ // TODO: cannot support tableau
+
+ private static final Logger logger =
LoggerFactory.getLogger(KylinClient.class);
+
+ private final KylinConnection conn;
+ private final Properties connProps;
+ private final CloseableHttpClient httpClient;
+ private final ObjectMapper jsonMapper;
+ private final static int POOL_MAX = 10;
+ private final static int POOL_MIN = 0;
+ private final static int RESPONSE_CODE_200 = 200;
+ private final static int RESPONSE_CODE_201 = 201;
+ private static final String APPLICATION = "application/json";
+ private static final String TIME_ZONE = "UTC";
+
+ public KylinClient(KylinConnection conn) {
+ entry(logger);
+ this.conn = conn;
+ this.connProps = conn.getConnectionProperties();
+ this.httpClient = buildHttpClient();
+ this.jsonMapper = new ObjectMapper();
+ jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ exit(logger);
+ }
+
+ private CloseableHttpClient buildHttpClient() {
+ HttpClientBuilder builder = HttpClients.custom();
+
+ // network timeout
+ int timeout = Integer.parseInt(connProps.getProperty("timeout", "0"));
+ RequestConfig rconf =
RequestConfig.custom().setConnectTimeout(timeout).setSocketTimeout(timeout).build();
+ builder.setDefaultRequestConfig(rconf);
+ logger.debug("use connection timeout " + timeout);
+
+ // SSL friendly
+ PoolingHttpClientConnectionManager cm;
+ if (isSSL()) {
+ try {
+ SSLContext sslContext = SSLContexts.custom()
+ .loadTrustMaterial((TrustStrategy) (x509Certificates,
s) -> true).build();
+ SSLConnectionSocketFactory sslsf = new
SSLConnectionSocketFactory(sslContext, (s, sslSession) -> true);
Review Comment:
## Server hostnames should be verified during SSL/TLS connections
<!--SONAR_ISSUE_KEY:AYSKSzxuqo1OziNXkSc0-->Enable server hostname
verification on this SSL/TLS connection. <p>See more on <a
href="https://sonarcloud.io/project/issues?id=apache_kylin&issues=AYSKSzxuqo1OziNXkSc0&open=AYSKSzxuqo1OziNXkSc0&pullRequest=2025">SonarCloud</a></p>
[Show more details](https://github.com/apache/kylin/security/code-scanning/2)
> Add Kylin5 Jdbc module
> ----------------------
>
> Key: KYLIN-5297
> URL: https://issues.apache.org/jira/browse/KYLIN-5297
> Project: Kylin
> Issue Type: New Feature
> Affects Versions: 5.0-alpha
> Reporter: mukvin
> Assignee: mukvin
> Priority: Major
> Fix For: 5.0-alpha
>
>
> Add Kylin JDBC module for kylin 5
--
This message was sent by Atlassian Jira
(v8.20.10#820010)