You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ja...@apache.org on 2022/06/15 18:54:59 UTC
[pinot] branch master updated: Add username and password support to JDBC driver (#8062)
This is an automated email from the ASF dual-hosted git repository.
jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new caf8d75582 Add username and password support to JDBC driver (#8062)
caf8d75582 is described below
commit caf8d755820d6bf27bc7daeb74ac35d2e70caa61
Author: Kartik Khare <kh...@gmail.com>
AuthorDate: Thu Jun 16 00:24:53 2022 +0530
Add username and password support to JDBC driver (#8062)
---
pinot-clients/pinot-jdbc-client/pom.xml | 3 +-
.../java/org/apache/pinot/client/PinotDriver.java | 33 +++++++++++---
.../org/apache/pinot/client/utils/DriverUtils.java | 50 ++++++++++++++++++++--
3 files changed, 77 insertions(+), 9 deletions(-)
diff --git a/pinot-clients/pinot-jdbc-client/pom.xml b/pinot-clients/pinot-jdbc-client/pom.xml
index b61deab966..32cad8cb9f 100644
--- a/pinot-clients/pinot-jdbc-client/pom.xml
+++ b/pinot-clients/pinot-jdbc-client/pom.xml
@@ -67,7 +67,8 @@
</dependency>
<dependency>
<groupId>org.apache.pinot</groupId>
- <artifactId>pinot-common</artifactId>
+ <artifactId>pinot-core</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
diff --git a/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/PinotDriver.java b/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/PinotDriver.java
index 4055d788d3..a01252b166 100644
--- a/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/PinotDriver.java
+++ b/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/PinotDriver.java
@@ -50,6 +50,7 @@ public class PinotDriver implements Driver {
public static final String DEFAULT_TENANT = "DefaultTenant";
public static final String INFO_SCHEME = "scheme";
public static final String INFO_HEADERS = "headers";
+
private SSLContext _sslContext = null;
public PinotDriver() { }
@@ -59,6 +60,23 @@ public class PinotDriver implements Driver {
_sslContext = sslContext;
}
+ /**
+ * Created connection to Pinot Controller from provided properties.
+ * The following properties can be provided -
+ * tenant - Specify the tenant for which this connection is being created. If not provided, DefaultTenant is used.
+ * The connection cannot handle queries for tables which are not present in the specified tenant.
+ * headers.Authorization - base64 token to query pinot. This is required in case Auth is enabled on pinot cluster.
+ * user - Name of the user for which auth is enabled.
+ * password - Password associated with the user for which auth is enabled.
+ * You can also specify username and password in the URL, e.g. jdbc:pinot://localhost:9000?user=Foo&password=Bar
+ * If username and password are specified at multiple places, the precedence takes place in the following order
+ * (header.Authorization property) > (username and password in URL) > (user and password specified in properties)
+ * @param url jdbc connection url containing pinot controller machine host:port.
+ * example - jdbc:pinot://localhost:9000
+ * @param info properties required for creating connection
+ * @return JDBC connection object to query pinot
+ * @throws SQLException
+ */
@Override
public Connection connect(String url, Properties info)
throws SQLException {
@@ -81,11 +99,9 @@ public class PinotDriver implements Driver {
}
}
- Map<String, String> headers =
- info.entrySet().stream().filter(entry -> entry.getKey().toString().startsWith(INFO_HEADERS + ".")).map(
- entry -> Pair
- .of(entry.getKey().toString().substring(INFO_HEADERS.length() + 1), entry.getValue().toString()))
- .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
+ Map<String, String> headers = getHeadersFromProperties(info);
+
+ DriverUtils.handleAuth(url, info, headers);
if (!headers.isEmpty()) {
factory.setHeaders(headers);
@@ -102,6 +118,13 @@ public class PinotDriver implements Driver {
}
}
+ private Map<String, String> getHeadersFromProperties(Properties info) {
+ return info.entrySet().stream().filter(entry -> entry.getKey().toString().startsWith(INFO_HEADERS + ".")).map(
+ entry -> Pair.of(entry.getKey().toString().substring(INFO_HEADERS.length() + 1),
+ entry.getValue().toString()))
+ .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
+ }
+
@Override
public boolean acceptsURL(String url)
throws SQLException {
diff --git a/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/utils/DriverUtils.java b/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/utils/DriverUtils.java
index 710a9d1725..3303bc2463 100644
--- a/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/utils/DriverUtils.java
+++ b/pinot-clients/pinot-jdbc-client/src/main/java/org/apache/pinot/client/utils/DriverUtils.java
@@ -20,24 +20,32 @@ package org.apache.pinot.client.utils;
import java.math.BigDecimal;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.pinot.common.config.TlsConfig;
import org.apache.pinot.common.utils.TlsUtils;
+import org.apache.pinot.core.auth.BasicAuthUtils;
import org.apache.pinot.spi.env.PinotConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DriverUtils {
- public static final String SCHEME = "jdbc";
+ public static final String SCHEME = "jdbc:";
public static final String DRIVER = "pinot";
public static final Logger LOG = LoggerFactory.getLogger(DriverUtils.class);
private static final String LIMIT_STATEMENT_REGEX = "\\s(limit)\\s";
@@ -45,6 +53,11 @@ public class DriverUtils {
// SSL Properties
public static final String PINOT_JDBC_TLS_PREFIX = "pinot.jdbc.tls";
+ // Auth Properties
+ public static final String USER_PROPERTY = "user";
+ public static final String PASSWORD_PROPERTY = "password";
+ public static final String AUTH_HEADER = "Authorization";
+
private DriverUtils() {
}
@@ -55,6 +68,22 @@ public class DriverUtils {
return TlsUtils.getSslContext();
}
+ public static void handleAuth(String url, Properties info, Map<String, String> headers)
+ throws SQLException {
+ Map<String, String> urlParams = DriverUtils.getURLParams(url);
+ info.putAll(urlParams);
+
+ if (info.contains(USER_PROPERTY) && !headers.containsKey(AUTH_HEADER)) {
+ String username = info.getProperty(USER_PROPERTY);
+ String password = info.getProperty(PASSWORD_PROPERTY, "");
+ if (StringUtils.isAnyEmpty(username, password)) {
+ throw new SQLException("Empty username or password provided.");
+ }
+ String authToken = BasicAuthUtils.toBasicAuthToken(username, password);
+ headers.put(AUTH_HEADER, authToken);
+ }
+ }
+
public static List<String> getBrokersFromURL(String url) {
if (url.toLowerCase().startsWith("jdbc:")) {
url = url.substring(5);
@@ -73,7 +102,7 @@ public class DriverUtils {
try {
String broker = brokers.get(0);
String[] hostPort = broker.split(":");
- URI uri = new URI(SCHEME + ":" + DRIVER, hostPort[0], hostPort[1]);
+ URI uri = new URI(SCHEME + DRIVER, hostPort[0], hostPort[1]);
return uri.toString();
} catch (Exception e) {
LOG.warn("Broker list is either empty or has incorrect format", e);
@@ -82,7 +111,7 @@ public class DriverUtils {
}
public static String getControllerFromURL(String url) {
- if (url.toLowerCase().startsWith("jdbc:")) {
+ if (url.regionMatches(true, 0, SCHEME, 0, SCHEME.length())) {
url = url.substring(5);
}
URI uri = URI.create(url);
@@ -90,6 +119,21 @@ public class DriverUtils {
return controllerUrl;
}
+ public static Map<String, String> getURLParams(String url) {
+ if (url.regionMatches(true, 0, SCHEME, 0, SCHEME.length())) {
+ url = url.substring(SCHEME.length());
+ }
+ URI uri = URI.create(url);
+ List<NameValuePair> params = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8);
+
+ Map<String, String> paramsMap = new HashMap<>();
+ for (NameValuePair param: params) {
+ paramsMap.put(param.getName(), param.getValue());
+ }
+
+ return paramsMap;
+ }
+
public static Integer getSQLDataType(String columnDataType) {
if (columnDataType == null) {
return Types.VARCHAR;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org