| /* |
| * 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.hive.jdbc; |
| |
| import java.io.IOException; |
| import java.net.InetAddress; |
| import java.net.URI; |
| import java.net.UnknownHostException; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.hive.conf.HiveConf; |
| import org.apache.hive.service.cli.HiveSQLException; |
| import org.apache.hive.service.rpc.thrift.TStatus; |
| import org.apache.hive.service.rpc.thrift.TStatusCode; |
| import org.apache.http.client.CookieStore; |
| import org.apache.http.cookie.Cookie; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class Utils { |
| static final Logger LOG = LoggerFactory.getLogger(Utils.class.getName()); |
| /** |
| * The required prefix for the connection URL. |
| */ |
| public static final String URL_PREFIX = "jdbc:hive2://"; |
| |
| /** |
| * If host is provided, without a port. |
| */ |
| static final String DEFAULT_PORT = "10000"; |
| |
| // To parse the intermediate URI as a Java URI, we'll give a dummy authority(dummyhost:00000). |
| // Later, we'll substitute the dummy authority for a resolved authority. |
| static final String dummyAuthorityString = "dummyhost:00000"; |
| |
| /** |
| * Hive's default database name |
| */ |
| static final String DEFAULT_DATABASE = "default"; |
| |
| private static final String URI_JDBC_PREFIX = "jdbc:"; |
| |
| private static final String URI_HIVE_PREFIX = "hive2:"; |
| |
| // This value is set to true by the setServiceUnavailableRetryStrategy() when the server returns 401. |
| // This value is used only when cookie is sent for authorization. In case the cookie is expired, |
| // client will send the actual credentials in the next connection request. |
| // If credentials are sent in the first request it self, then no need to retry. |
| static final String HIVE_SERVER2_RETRY_KEY = "hive.server2.retryserver"; |
| static final String HIVE_SERVER2_SENT_CREDENTIALS = "hive.server2.sentCredentials"; |
| static final String HIVE_SERVER2_CONST_TRUE = "true"; |
| static final String HIVE_SERVER2_CONST_FALSE = "false"; |
| |
| public static class JdbcConnectionParams { |
| // Note on client side parameter naming convention: |
| // Prefer using a shorter camelCase param name instead of using the same name as the |
| // corresponding |
| // HiveServer2 config. |
| // For a jdbc url: jdbc:hive2://<host>:<port>/dbName;sess_var_list?hive_conf_list#hive_var_list, |
| // client side params are specified in sess_var_list |
| |
| // Client param names: |
| |
| // Retry setting |
| public static final String RETRIES = "retries"; |
| public static final String RETRY_INTERVAL = "retryInterval"; |
| |
| public static final String AUTH_TYPE = "auth"; |
| // We're deprecating this variable's name. |
| public static final String AUTH_QOP_DEPRECATED = "sasl.qop"; |
| public static final String AUTH_QOP = "saslQop"; |
| public static final String AUTH_SIMPLE = "noSasl"; |
| public static final String AUTH_TOKEN = "delegationToken"; |
| public static final String AUTH_USER = "user"; |
| public static final String AUTH_PRINCIPAL = "principal"; |
| public static final String AUTH_PASSWD = "password"; |
| public static final String AUTH_KERBEROS_AUTH_TYPE = "kerberosAuthType"; |
| public static final String AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT = "fromSubject"; |
| public static final String AUTH_KERBEROS_ENABLE_CANONICAL_HOSTNAME_CHECK = "kerberosEnableCanonicalHostnameCheck"; |
| public static final String AUTH_TYPE_JWT = "jwt"; |
| public static final String AUTH_TYPE_JWT_KEY = "jwt"; |
| public static final String AUTH_JWT_ENV = "JWT"; |
| // JdbcConnection param which specifies if we need to use a browser to do |
| // authentication. |
| // JdbcConnectionParam which specifies if the authMode is done via a browser |
| public static final String AUTH_SSO_BROWSER_MODE = "browser"; |
| public static final String AUTH_SSO_TOKEN_MODE = "token"; |
| // connection parameter used to specify a port number to listen on in case of |
| // browser mode. |
| public static final String AUTH_BROWSER_RESPONSE_PORT = "browserResponsePort"; |
| // connection parameter used to specify the timeout in seconds for the browser mode |
| public static final String AUTH_BROWSER_RESPONSE_TIMEOUT_SECS = "browserResponseTimeout"; |
| // connection parameter to optionally disable the SSL validation done when using |
| // browser based authentication. Useful mostly for testing/dev purposes. |
| // By default, SSL validation is done unless this parameter is set to true. |
| public static final String AUTH_BROWSER_DISABLE_SSL_VALIDATION = "browserDisableSslCheck"; |
| public static final String ANONYMOUS_USER = "anonymous"; |
| public static final String ANONYMOUS_PASSWD = "anonymous"; |
| public static final String USE_SSL = "ssl"; |
| public static final String SSL_TRUST_STORE = "sslTrustStore"; |
| public static final String SSL_TRUST_STORE_PASSWORD = "trustStorePassword"; |
| public static final String SSL_TRUST_STORE_TYPE = "trustStoreType"; |
| public static final String SSL_TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm"; |
| // We're deprecating the name and placement of this in the parsed map (from hive conf vars to |
| // hive session vars). |
| static final String TRANSPORT_MODE_DEPRECATED = "hive.server2.transport.mode"; |
| public static final String TRANSPORT_MODE = "transportMode"; |
| // We're deprecating the name and placement of this in the parsed map (from hive conf vars to |
| // hive session vars). |
| static final String HTTP_PATH_DEPRECATED = "hive.server2.thrift.http.path"; |
| public static final String HTTP_PATH = "httpPath"; |
| public static final String SERVICE_DISCOVERY_MODE = "serviceDiscoveryMode"; |
| public static final String PROPERTY_DRIVER = "driver"; |
| public static final String PROPERTY_URL = "url"; |
| // Don't use dynamic service discovery |
| static final String SERVICE_DISCOVERY_MODE_NONE = "none"; |
| // Use ZooKeeper for indirection while using dynamic service discovery |
| public static final String SERVICE_DISCOVERY_MODE_ZOOKEEPER = "zooKeeper"; |
| public static final String SERVICE_DISCOVERY_MODE_ZOOKEEPER_HA = "zooKeeperHA"; |
| public static final String ZOOKEEPER_NAMESPACE = "zooKeeperNamespace"; |
| public static final String ZOOKEEPER_SSL_ENABLE = "zooKeeperSSLEnable"; |
| public static final String ZOOKEEPER_KEYSTORE_LOCATION = "zooKeeperKeystoreLocation"; |
| public static final String ZOOKEEPER_KEYSTORE_PASSWORD= "zooKeeperKeystorePassword"; |
| public static final String ZOOKEEPER_TRUSTSTORE_LOCATION = "zooKeeperTruststoreLocation"; |
| public static final String ZOOKEEPER_TRUSTSTORE_PASSWORD = "zooKeeperTruststorePassword"; |
| // Default namespace value on ZooKeeper. |
| // This value is used if the param "zooKeeperNamespace" is not specified in the JDBC Uri. |
| static final String ZOOKEEPER_DEFAULT_NAMESPACE = "hiveserver2"; |
| static final String ZOOKEEPER_ACTIVE_PASSIVE_HA_DEFAULT_NAMESPACE = "hs2ActivePassiveHA"; |
| static final String COOKIE_AUTH = "cookieAuth"; |
| static final String COOKIE_AUTH_FALSE = "false"; |
| static final String COOKIE_NAME = "cookieName"; |
| // The default value of the cookie name when CookieAuth=true |
| static final String DEFAULT_COOKIE_NAMES_HS2 = "hive.server2.auth"; |
| // The http header prefix for additional headers which have to be appended to the request |
| static final String HTTP_HEADER_PREFIX = "http.header."; |
| // Request tracking |
| static final String JDBC_PARAM_REQUEST_TRACK = "requestTrack"; |
| // Set the fetchSize |
| static final String FETCH_SIZE = "fetchSize"; |
| static final String INIT_FILE = "initFile"; |
| static final String WM_POOL = "wmPool"; |
| // Cookie prefix |
| static final String HTTP_COOKIE_PREFIX = "http.cookie."; |
| // Create external purge table by default |
| static final String CREATE_TABLE_AS_EXTERNAL = "hiveCreateAsExternalLegacy"; |
| public static final String SOCKET_TIMEOUT = "socketTimeout"; |
| static final String THRIFT_CLIENT_MAX_MESSAGE_SIZE = "thrift.client.max.message.size"; |
| |
| // We support ways to specify application name modeled after some existing DBs, since |
| // there's no standard approach. |
| // MSSQL: applicationName https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url |
| // Postgres 9~: ApplicationName https://jdbc.postgresql.org/documentation/91/connect.html |
| // Note: various ODBC names used include "Application Name", "APP", etc. Add those? |
| static final String[] APPLICATION = new String[] { "applicationName", "ApplicationName" }; |
| |
| // --------------- Begin 2 way ssl options ------------------------- |
| // Use two way ssl. This param will take effect only when ssl=true |
| static final String USE_TWO_WAY_SSL = "twoWay"; |
| static final String TRUE = "true"; |
| static final String SSL_KEY_STORE = "sslKeyStore"; |
| static final String SSL_KEY_STORE_PASSWORD = "keyStorePassword"; |
| static final String SSL_KEY_STORE_TYPE = "JKS"; |
| static final String SUNX509_ALGORITHM_STRING = "SunX509"; |
| static final String SUNJSSE_ALGORITHM_STRING = "SunJSSE"; |
| // --------------- End 2 way ssl options ---------------------------- |
| |
| static final String SSL_STORE_PASSWORD_PATH = "storePasswordPath"; |
| |
| private static final String HIVE_VAR_PREFIX = "hivevar:"; |
| public static final String HIVE_CONF_PREFIX = "hiveconf:"; |
| private String host = null; |
| private int port = 0; |
| private String jdbcUriString; |
| private String dbName = DEFAULT_DATABASE; |
| private Map<String,String> hiveConfs = new LinkedHashMap<String,String>(); |
| private Map<String,String> hiveVars = new LinkedHashMap<String,String>(); |
| private Map<String,String> sessionVars = new LinkedHashMap<String,String>(); |
| private boolean isEmbeddedMode = false; |
| private String suppliedURLAuthority; |
| private String zooKeeperEnsemble = null; |
| private boolean zooKeeperSslEnabled = false; |
| private String zookeeperKeyStoreLocation = ""; |
| private String zookeeperKeyStorePassword = ""; |
| private String zookeeperTrustStoreLocation = ""; |
| private String zookeeperTrustStorePassword = ""; |
| private String currentHostZnodePath; |
| private final List<String> rejectedHostZnodePaths = new ArrayList<String>(); |
| |
| // HiveConf parameters |
| public static final String HIVE_DEFAULT_NULLS_LAST_KEY = |
| HIVE_CONF_PREFIX + HiveConf.ConfVars.HIVE_DEFAULT_NULLS_LAST.varname; |
| |
| public JdbcConnectionParams() { |
| } |
| |
| public JdbcConnectionParams(JdbcConnectionParams params) { |
| this.host = params.host; |
| this.port = params.port; |
| this.jdbcUriString = params.jdbcUriString; |
| this.dbName = params.dbName; |
| this.hiveConfs.putAll(params.hiveConfs); |
| this.hiveVars.putAll(params.hiveVars); |
| this.sessionVars.putAll(params.sessionVars); |
| this.isEmbeddedMode = params.isEmbeddedMode; |
| this.suppliedURLAuthority = params.suppliedURLAuthority; |
| this.zooKeeperEnsemble = params.zooKeeperEnsemble; |
| this.zooKeeperSslEnabled = params.zooKeeperSslEnabled; |
| this.zookeeperKeyStoreLocation = params.zookeeperKeyStoreLocation; |
| this.zookeeperKeyStorePassword = params.zookeeperKeyStorePassword; |
| this.zookeeperTrustStoreLocation = params.zookeeperTrustStoreLocation; |
| this.zookeeperTrustStorePassword = params.zookeeperTrustStorePassword; |
| |
| this.currentHostZnodePath = params.currentHostZnodePath; |
| this.rejectedHostZnodePaths.addAll(rejectedHostZnodePaths); |
| } |
| |
| public String getHost() { |
| return host; |
| } |
| |
| public int getPort() { |
| return port; |
| } |
| |
| public String getJdbcUriString() { |
| return jdbcUriString; |
| } |
| |
| public String getDbName() { |
| return dbName; |
| } |
| |
| public Map<String, String> getHiveConfs() { |
| return hiveConfs; |
| } |
| |
| public Map<String, String> getHiveVars() { |
| return hiveVars; |
| } |
| |
| public boolean isEmbeddedMode() { |
| return isEmbeddedMode; |
| } |
| |
| public Map<String, String> getSessionVars() { |
| return sessionVars; |
| } |
| |
| public String getSuppliedURLAuthority() { |
| return suppliedURLAuthority; |
| } |
| |
| public String getZooKeeperEnsemble() { |
| return zooKeeperEnsemble; |
| } |
| public boolean isZooKeeperSslEnabled() { |
| return zooKeeperSslEnabled; |
| } |
| |
| public String getZookeeperKeyStoreLocation() { |
| return zookeeperKeyStoreLocation; |
| } |
| |
| public String getZookeeperKeyStorePassword() { |
| return zookeeperKeyStorePassword; |
| } |
| |
| public String getZookeeperTrustStoreLocation() { |
| return zookeeperTrustStoreLocation; |
| } |
| |
| public String getZookeeperTrustStorePassword() { |
| return zookeeperTrustStorePassword; |
| } |
| |
| public List<String> getRejectedHostZnodePaths() { |
| return rejectedHostZnodePaths; |
| } |
| |
| public String getCurrentHostZnodePath() { |
| return currentHostZnodePath; |
| } |
| |
| public void setHost(String host) { |
| this.host = host; |
| } |
| |
| public void setPort(int port) { |
| this.port = port; |
| } |
| |
| public void setJdbcUriString(String jdbcUriString) { |
| this.jdbcUriString = jdbcUriString; |
| } |
| |
| public void setDbName(String dbName) { |
| this.dbName = dbName; |
| } |
| |
| public void setHiveConfs(Map<String, String> hiveConfs) { |
| this.hiveConfs = hiveConfs; |
| } |
| |
| public void setHiveVars(Map<String, String> hiveVars) { |
| this.hiveVars = hiveVars; |
| } |
| |
| public void setEmbeddedMode(boolean embeddedMode) { |
| this.isEmbeddedMode = embeddedMode; |
| } |
| |
| public void setSessionVars(Map<String, String> sessionVars) { |
| this.sessionVars = sessionVars; |
| } |
| |
| public void setSuppliedURLAuthority(String suppliedURLAuthority) { |
| this.suppliedURLAuthority = suppliedURLAuthority; |
| } |
| |
| public void setZooKeeperEnsemble(String zooKeeperEnsemble) { |
| this.zooKeeperEnsemble = zooKeeperEnsemble; |
| } |
| |
| public void setZooKeeperSslEnabled(boolean zooKeeperSslEnabled) { |
| this.zooKeeperSslEnabled = zooKeeperSslEnabled; |
| } |
| |
| public void setZookeeperKeyStoreLocation(String zookeeperKeyStoreLocation) { |
| this.zookeeperKeyStoreLocation = zookeeperKeyStoreLocation; |
| } |
| |
| public void setZookeeperKeyStorePassword(String zookeeperKeyStorePassword) { |
| this.zookeeperKeyStorePassword = zookeeperKeyStorePassword; |
| } |
| |
| public void setZookeeperTrustStoreLocation(String zookeeperTrustStoreLocation) { |
| this.zookeeperTrustStoreLocation = zookeeperTrustStoreLocation; |
| } |
| |
| public void setZookeeperTrustStorePassword(String zookeeperTrustStorePassword) { |
| this.zookeeperTrustStorePassword = zookeeperTrustStorePassword; |
| } |
| |
| public void setCurrentHostZnodePath(String currentHostZnodePath) { |
| this.currentHostZnodePath = currentHostZnodePath; |
| } |
| } |
| |
| // Verify success or success_with_info status, else throw SQLException |
| static void verifySuccessWithInfo(TStatus status) throws SQLException { |
| verifySuccess(status, true); |
| } |
| |
| // Verify success status, else throw SQLException |
| static void verifySuccess(TStatus status) throws SQLException { |
| verifySuccess(status, false); |
| } |
| |
| // Verify success and optionally with_info status, else throw SQLException |
| static void verifySuccess(TStatus status, boolean withInfo) throws SQLException { |
| if (status.getStatusCode() == TStatusCode.SUCCESS_STATUS || |
| (withInfo && status.getStatusCode() == TStatusCode.SUCCESS_WITH_INFO_STATUS)) { |
| return; |
| } |
| throw new HiveSQLException(status); |
| } |
| |
| public static JdbcConnectionParams parseURL(String uri) throws JdbcUriParseException, |
| SQLException, ZooKeeperHiveClientException { |
| return parseURL(uri, new Properties()); |
| } |
| /** |
| * Parse JDBC connection URL |
| * The new format of the URL is: |
| * jdbc:hive2://<host1>:<port1>,<host2>:<port2>/dbName;sess_var_list?hive_conf_list#hive_var_list |
| * where the optional sess, conf and var lists are semicolon separated <key>=<val> pairs. |
| * For utilizing dynamic service discovery with HiveServer2 multiple comma separated host:port pairs can |
| * be specified as shown above. |
| * The JDBC driver resolves the list of uris and picks a specific server instance to connect to. |
| * Currently, dynamic service discovery using ZooKeeper is supported, in which case the host:port pairs represent a ZooKeeper ensemble. |
| * |
| * As before, if the host/port is not specified, it the driver runs an embedded hive. |
| * examples - |
| * jdbc:hive2://ubuntu:11000/db2?hive.cli.conf.printheader=true;hive.exec.mode.local.auto.inputbytes.max=9999#stab=salesTable;icol=customerID |
| * jdbc:hive2://?hive.cli.conf.printheader=true;hive.exec.mode.local.auto.inputbytes.max=9999#stab=salesTable;icol=customerID |
| * jdbc:hive2://ubuntu:11000/db2;user=foo;password=bar |
| * |
| * Connect to http://server:10001/hs2, with specified basicAuth credentials and initial database: |
| * jdbc:hive2://server:10001/db;user=foo;password=bar?hive.server2.transport.mode=http;hive.server2.thrift.http.path=hs2 |
| * |
| * @param uri |
| * @return |
| * @throws SQLException |
| */ |
| public static JdbcConnectionParams parseURL(String uri, Properties info) |
| throws JdbcUriParseException, SQLException, ZooKeeperHiveClientException { |
| JdbcConnectionParams connParams = extractURLComponents(uri, info); |
| if (ZooKeeperHiveClientHelper.isZkDynamicDiscoveryMode(connParams.getSessionVars())) { |
| configureConnParamsFromZooKeeper(connParams); |
| } |
| handleAllDeprecations(connParams); |
| return connParams; |
| } |
| |
| /** |
| * This method handles the base parsing of the given jdbc uri. Some of JdbcConnectionParams |
| * returned from this method are updated if ZooKeeper is used for service discovery |
| * |
| * @param uri |
| * @param info |
| * @return |
| * @throws JdbcUriParseException |
| */ |
| public static JdbcConnectionParams extractURLComponents(String uri, Properties info) |
| throws JdbcUriParseException { |
| JdbcConnectionParams connParams = new JdbcConnectionParams(); |
| if (!uri.startsWith(URL_PREFIX)) { |
| throw new JdbcUriParseException("Bad URL format: Missing prefix " + URL_PREFIX); |
| } |
| |
| // For URLs with no other configuration |
| // Don't parse them, but set embedded mode as true |
| if (uri.equalsIgnoreCase(URL_PREFIX)) { |
| connParams.setEmbeddedMode(true); |
| return connParams; |
| } |
| |
| // The JDBC URI now supports specifying multiple host:port if dynamic service discovery is |
| // configured on HiveServer2 (like: host1:port1,host2:port2,host3:port3) |
| // We'll extract the authorities (host:port combo) from the URI, extract session vars, hive |
| // confs & hive vars by parsing it as a Java URI. |
| String authorityFromClientJdbcURL = getAuthorityFromJdbcURL(uri); |
| if ((authorityFromClientJdbcURL == null) || (authorityFromClientJdbcURL.isEmpty())) { |
| // Given uri of the form: |
| // jdbc:hive2:///dbName;sess_var_list?hive_conf_list#hive_var_list |
| connParams.setEmbeddedMode(true); |
| } else { |
| connParams.setSuppliedURLAuthority(authorityFromClientJdbcURL); |
| uri = uri.replace(authorityFromClientJdbcURL, dummyAuthorityString); |
| } |
| |
| // Now parse the connection uri with dummy authority |
| URI jdbcURI = URI.create(uri.substring(URI_JDBC_PREFIX.length())); |
| |
| // key=value pattern |
| Pattern pattern = Pattern.compile("([^;]*)=([^;]*)[;]?"); |
| |
| // dbname and session settings |
| String sessVars = jdbcURI.getPath(); |
| if ((sessVars != null) && !sessVars.isEmpty()) { |
| String dbName = ""; |
| // removing leading '/' returned by getPath() |
| sessVars = sessVars.substring(1); |
| if (!sessVars.contains(";")) { |
| // only dbname is provided |
| dbName = sessVars; |
| } else { |
| // we have dbname followed by session parameters |
| dbName = sessVars.substring(0, sessVars.indexOf(';')); |
| sessVars = sessVars.substring(sessVars.indexOf(';') + 1); |
| if (sessVars != null) { |
| Matcher sessMatcher = pattern.matcher(sessVars); |
| while (sessMatcher.find()) { |
| if (connParams.getSessionVars().put(sessMatcher.group(1), |
| sessMatcher.group(2)) != null) { |
| throw new JdbcUriParseException( |
| "Bad URL format: Multiple values for property " + sessMatcher.group(1)); |
| } |
| } |
| } |
| } |
| if (!dbName.isEmpty()) { |
| connParams.setDbName(dbName); |
| } |
| } |
| |
| // parse hive conf settings |
| String confStr = jdbcURI.getQuery(); |
| if (confStr != null) { |
| Matcher confMatcher = pattern.matcher(confStr); |
| while (confMatcher.find()) { |
| connParams.getHiveConfs().put(confMatcher.group(1), confMatcher.group(2)); |
| } |
| } |
| |
| // parse hive var settings |
| String varStr = jdbcURI.getFragment(); |
| if (varStr != null) { |
| Matcher varMatcher = pattern.matcher(varStr); |
| while (varMatcher.find()) { |
| connParams.getHiveVars().put(varMatcher.group(1), varMatcher.group(2)); |
| } |
| } |
| |
| // Apply configs supplied in the JDBC connection properties object |
| for (Map.Entry<Object, Object> kv : info.entrySet()) { |
| if ((kv.getKey() instanceof String)) { |
| String key = (String) kv.getKey(); |
| if (key.startsWith(JdbcConnectionParams.HIVE_VAR_PREFIX)) { |
| connParams.getHiveVars().put(key.substring(JdbcConnectionParams.HIVE_VAR_PREFIX.length()), |
| info.getProperty(key)); |
| } else if (key.startsWith(JdbcConnectionParams.HIVE_CONF_PREFIX)) { |
| connParams.getHiveConfs().put( |
| key.substring(JdbcConnectionParams.HIVE_CONF_PREFIX.length()), info.getProperty(key)); |
| } |
| } |
| } |
| |
| // Extract user/password from JDBC connection properties if its not supplied |
| // in the connection URL |
| if (!connParams.getSessionVars().containsKey(JdbcConnectionParams.AUTH_USER)) { |
| if (info.containsKey(JdbcConnectionParams.AUTH_USER)) { |
| connParams.getSessionVars().put(JdbcConnectionParams.AUTH_USER, |
| info.getProperty(JdbcConnectionParams.AUTH_USER)); |
| } |
| if (info.containsKey(JdbcConnectionParams.AUTH_PASSWD)) { |
| connParams.getSessionVars().put(JdbcConnectionParams.AUTH_PASSWD, |
| info.getProperty(JdbcConnectionParams.AUTH_PASSWD)); |
| } |
| } |
| |
| if (!connParams.getSessionVars().containsKey(JdbcConnectionParams.AUTH_PASSWD)) { |
| if (info.containsKey(JdbcConnectionParams.AUTH_USER)) { |
| connParams.getSessionVars().put(JdbcConnectionParams.AUTH_USER, |
| info.getProperty(JdbcConnectionParams.AUTH_USER)); |
| } |
| if (info.containsKey(JdbcConnectionParams.AUTH_PASSWD)) { |
| connParams.getSessionVars().put(JdbcConnectionParams.AUTH_PASSWD, |
| info.getProperty(JdbcConnectionParams.AUTH_PASSWD)); |
| } |
| } |
| |
| if (info.containsKey(JdbcConnectionParams.AUTH_TYPE)) { |
| connParams.getSessionVars().put(JdbcConnectionParams.AUTH_TYPE, |
| info.getProperty(JdbcConnectionParams.AUTH_TYPE)); |
| } |
| // Extract host, port |
| if (connParams.isEmbeddedMode()) { |
| // In case of embedded mode we were supplied with an empty authority. |
| // So we never substituted the authority with a dummy one. |
| connParams.setHost(jdbcURI.getHost()); |
| connParams.setPort(jdbcURI.getPort()); |
| } else { |
| String authorityStr = connParams.getSuppliedURLAuthority(); |
| // If we're using ZooKeeper, the final host, port will be read from ZooKeeper |
| // (in a different method call). Therefore, we put back the original authority string |
| // (which basically is the ZooKeeper ensemble) back in the uri |
| if (ZooKeeperHiveClientHelper.isZkDynamicDiscoveryMode(connParams.getSessionVars())) { |
| uri = uri.replace(dummyAuthorityString, authorityStr); |
| // Set ZooKeeper ensemble in connParams for later use |
| connParams.setZooKeeperEnsemble(authorityStr); |
| ZooKeeperHiveClientHelper.setZkSSLParams(connParams); |
| } else { |
| URI jdbcBaseURI = URI.create(URI_HIVE_PREFIX + "//" + authorityStr); |
| // Check to prevent unintentional use of embedded mode. A missing "/" |
| // to separate the 'path' portion of URI can result in this. |
| // The missing "/" common typo while using secure mode, eg of such url - |
| // jdbc:hive2://localhost:10000;principal=hive/HiveServer2Host@YOUR-REALM.COM |
| if (jdbcBaseURI.getAuthority() != null) { |
| String host = jdbcBaseURI.getHost(); |
| int port = jdbcBaseURI.getPort(); |
| if (host == null) { |
| throw new JdbcUriParseException( |
| "Bad URL format. Hostname not found " + " in authority part of the url: " |
| + jdbcBaseURI.getAuthority() + ". Are you missing a '/' after the hostname ?"); |
| } |
| // Set the port to default value; we do support jdbc url like: |
| // jdbc:hive2://localhost/db |
| if (port <= 0) { |
| port = Integer.parseInt(Utils.DEFAULT_PORT); |
| } |
| connParams.setHost(jdbcBaseURI.getHost()); |
| connParams.setPort(jdbcBaseURI.getPort()); |
| } |
| // We check for invalid host, port while configuring connParams with configureConnParams() |
| authorityStr = connParams.getHost() + ":" + connParams.getPort(); |
| LOG.debug("Resolved authority: " + authorityStr); |
| uri = uri.replace(dummyAuthorityString, authorityStr); |
| } |
| } |
| connParams.setJdbcUriString(uri); |
| return connParams; |
| } |
| |
| // Configure using ZooKeeper |
| static void configureConnParamsFromZooKeeper(JdbcConnectionParams connParams) |
| throws ZooKeeperHiveClientException, JdbcUriParseException { |
| ZooKeeperHiveClientHelper.configureConnParams(connParams); |
| String authorityStr = connParams.getHost() + ":" + connParams.getPort(); |
| LOG.debug("Resolved authority: " + authorityStr); |
| String jdbcUriString = connParams.getJdbcUriString(); |
| // Replace ZooKeeper ensemble from the authority component of the JDBC Uri provided by the |
| // client, by the host:port of the resolved server instance we will connect to |
| connParams.setJdbcUriString( |
| jdbcUriString.replace(getAuthorityFromJdbcURL(jdbcUriString), authorityStr)); |
| } |
| |
| private static void handleAllDeprecations(JdbcConnectionParams connParams) { |
| // Handle all deprecations here: |
| String newUsage; |
| String usageUrlBase = "jdbc:hive2://<host>:<port>/dbName;"; |
| // Handle deprecation of AUTH_QOP_DEPRECATED |
| newUsage = usageUrlBase + JdbcConnectionParams.AUTH_QOP + "=<qop_value>"; |
| handleParamDeprecation(connParams.getSessionVars(), connParams.getSessionVars(), |
| JdbcConnectionParams.AUTH_QOP_DEPRECATED, JdbcConnectionParams.AUTH_QOP, newUsage); |
| |
| // Handle deprecation of TRANSPORT_MODE_DEPRECATED |
| newUsage = usageUrlBase + JdbcConnectionParams.TRANSPORT_MODE + "=<transport_mode_value>"; |
| handleParamDeprecation(connParams.getHiveConfs(), connParams.getSessionVars(), |
| JdbcConnectionParams.TRANSPORT_MODE_DEPRECATED, JdbcConnectionParams.TRANSPORT_MODE, |
| newUsage); |
| |
| // Handle deprecation of HTTP_PATH_DEPRECATED |
| newUsage = usageUrlBase + JdbcConnectionParams.HTTP_PATH + "=<http_path_value>"; |
| handleParamDeprecation(connParams.getHiveConfs(), connParams.getSessionVars(), |
| JdbcConnectionParams.HTTP_PATH_DEPRECATED, JdbcConnectionParams.HTTP_PATH, newUsage); |
| } |
| |
| /** |
| * Remove the deprecatedName param from the fromMap and put the key value in the toMap. |
| * Also log a deprecation message for the client. |
| * @param fromMap |
| * @param toMap |
| * @param deprecatedName |
| * @param newName |
| * @param newUsage |
| */ |
| private static void handleParamDeprecation(Map<String, String> fromMap, Map<String, String> toMap, |
| String deprecatedName, String newName, String newUsage) { |
| if (fromMap.containsKey(deprecatedName)) { |
| LOG.warn("***** JDBC param deprecation *****"); |
| LOG.warn("The use of " + deprecatedName + " is deprecated."); |
| LOG.warn("Please use " + newName +" like so: " + newUsage); |
| String paramValue = fromMap.remove(deprecatedName); |
| toMap.put(newName, paramValue); |
| } |
| } |
| |
| /** |
| * Get the authority string from the supplied uri, which could potentially contain multiple |
| * host:port pairs. |
| * |
| * @param uri |
| * @return |
| * @throws JdbcUriParseException |
| */ |
| private static String getAuthorityFromJdbcURL(String uri) throws JdbcUriParseException { |
| String authorities; |
| /** |
| * For a jdbc uri like: |
| * jdbc:hive2://<host1>:<port1>,<host2>:<port2>/dbName;sess_var_list?conf_list#var_list Extract |
| * the uri host:port list starting after "jdbc:hive2://", till the 1st "/" or "?" or "#" |
| * whichever comes first & in the given order Examples: |
| * jdbc:hive2://host1:port1,host2:port2,host3:port3/db;k1=v1?k2=v2#k3=v3 |
| * jdbc:hive2://host1:port1,host2:port2,host3:port3/;k1=v1?k2=v2#k3=v3 |
| * jdbc:hive2://host1:port1,host2:port2,host3:port3?k2=v2#k3=v3 |
| * jdbc:hive2://host1:port1,host2:port2,host3:port3#k3=v3 |
| */ |
| int fromIndex = Utils.URL_PREFIX.length(); |
| int toIndex = -1; |
| for (String toIndexChar : Arrays.asList("/", "?", "#")) { |
| toIndex = uri.indexOf(toIndexChar, fromIndex); |
| if (toIndex > 0) { |
| break; |
| } |
| } |
| if (toIndex < 0) { |
| authorities = uri.substring(fromIndex); |
| } else { |
| authorities = uri.substring(fromIndex, toIndex); |
| } |
| return authorities; |
| } |
| |
| /** |
| * Read the next server coordinates (host:port combo) from ZooKeeper. Ignore the znodes already |
| * explored. Also update the host, port, jdbcUriString and other configs published by the server. |
| * |
| * @param connParams |
| * @return true if new server info is retrieved successfully |
| */ |
| static boolean updateConnParamsFromZooKeeper(JdbcConnectionParams connParams) { |
| // Add current host to the rejected list |
| connParams.getRejectedHostZnodePaths().add(connParams.getCurrentHostZnodePath()); |
| String oldServerHost = connParams.getHost(); |
| int oldServerPort = connParams.getPort(); |
| // Update connection params (including host, port) from ZooKeeper |
| try { |
| ZooKeeperHiveClientHelper.configureConnParams(connParams); |
| connParams.setJdbcUriString(connParams.getJdbcUriString().replace( |
| oldServerHost + ":" + oldServerPort, connParams.getHost() + ":" + connParams.getPort())); |
| LOG.info("Selected HiveServer2 instance with uri: " + connParams.getJdbcUriString()); |
| } catch(ZooKeeperHiveClientException e) { |
| LOG.error(e.getMessage()); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Takes a version string delimited by '.' and '-' characters |
| * and returns a partial version. |
| * |
| * @param fullVersion |
| * version string. |
| * @param position |
| * position of version string to get starting at 0. eg, for a X.x.xxx |
| * string, 0 will return the major version, 1 will return minor |
| * version. |
| * @return version part, or -1 if version string was malformed. |
| */ |
| static int getVersionPart(String fullVersion, int position) { |
| int version = -1; |
| try { |
| String[] tokens = fullVersion.split("[\\.-]"); //$NON-NLS-1$ |
| |
| if (tokens != null && tokens.length > 1 && tokens[position] != null) { |
| version = Integer.parseInt(tokens[position]); |
| } |
| } catch (Exception e) { |
| version = -1; |
| } |
| return version; |
| } |
| |
| /** |
| * The function iterates through the list of cookies in the cookiestore and tries to |
| * match them with the cookieName. If there is a match, the cookieStore already |
| * has a valid cookie and the client need not send Credentials for validation purpose. |
| * @param cookieStore The cookie Store |
| * @param cookieName Name of the cookie which needs to be validated |
| * @param isSSL Whether this is a http/https connection |
| * @return true or false based on whether the client needs to send the credentials or |
| * not to the server. |
| */ |
| static boolean needToSendCredentials(CookieStore cookieStore, String cookieName, boolean isSSL) { |
| if (cookieName == null || cookieStore == null) { |
| return true; |
| } |
| |
| List<Cookie> cookies = cookieStore.getCookies(); |
| |
| for (Cookie c : cookies) { |
| // If this is a secured cookie and the current connection is non-secured, |
| // then, skip this cookie. We need to skip this cookie because, the cookie |
| // replay will not be transmitted to the server. |
| if (c.isSecure() && !isSSL) { |
| continue; |
| } |
| if (c.getName().equals(cookieName)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public static String parsePropertyFromUrl(final String url, final String key) { |
| String[] tokens = url.split(";"); |
| for (String token : tokens) { |
| if (token.trim().startsWith(key.trim() + "=")) { |
| return token.trim().substring((key.trim() + "=").length()); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Method to get canonical-ized hostname, given a hostname (possibly a CNAME). |
| * This should allow for service-principals to use simplified CNAMEs. |
| * @param hostName The hostname to be canonical-ized. |
| * @return Given a CNAME, the canonical-ized hostname is returned. If not found, the original hostname is returned. |
| */ |
| public static String getCanonicalHostName(String hostName) { |
| try { |
| return InetAddress.getByName(hostName).getCanonicalHostName(); |
| } |
| catch(UnknownHostException exception) { |
| LOG.warn("Could not retrieve canonical hostname for " + hostName, exception); |
| return hostName; |
| } |
| } |
| |
| /** |
| * Method to get the password from the credential provider |
| * @param providerPath provider path |
| * @param key alias name |
| * @return password |
| */ |
| private static String getPasswordFromCredentialProvider(String providerPath, String key) { |
| try { |
| if (providerPath != null) { |
| Configuration conf = new Configuration(); |
| conf.set("hadoop.security.credential.provider.path", providerPath); |
| char[] password = conf.getPassword(key); |
| if (password != null) { |
| return new String(password); |
| } |
| } |
| } catch(IOException exception) { |
| LOG.warn("Could not retrieve password for " + key, exception); |
| } |
| return null; |
| } |
| |
| /** |
| * Method to get the password from the configuration map if available. Otherwise, get it from the credential provider |
| * @param confMap configuration map |
| * @param key param |
| * @return password |
| */ |
| public static String getPassword(Map<String, String> confMap, String key) { |
| String password = confMap.get(key); |
| if (password == null) { |
| password = getPasswordFromCredentialProvider(confMap.get(JdbcConnectionParams.SSL_STORE_PASSWORD_PATH), key); |
| } |
| return password; |
| } |
| } |