diff --git a/docs/interpreter/jdbc.md b/docs/interpreter/jdbc.md index 2c1d2f794c6..57bee4dcff4 100644 --- a/docs/interpreter/jdbc.md +++ b/docs/interpreter/jdbc.md @@ -171,7 +171,7 @@ There are more JDBC interpreter properties you can specify like below. zeppelin.jdbc.auth.kerberos.proxy.enable -      When auth type is Kerberos, enable/disable Kerberos proxy with the login user to get the connection. Default value is true. + When auth type is Kerberos, enable/disable Kerberos proxy with the login user to get the connection. Default value is true. default.jceks.file @@ -202,7 +202,7 @@ To bind the interpreters created in the interpreter setting page, click the gear -Select(blue) or deselect(white) the interpreter buttons depending on your use cases. +Select(blue) or deselect(white) the interpreter buttons depending on your use cases. If you need to use more than one interpreter in the notebook, activate several buttons. Don't forget to click `Save` button, or you will face `Interpreter *** is not found` error. @@ -285,7 +285,7 @@ An example settings of interpreter for the two data sources, each of which has i ##### Usage -Test of execution *precode* for each data source. +Test of execution *precode* for each data source. ```sql %jdbc @@ -480,7 +480,7 @@ Here are some examples you can refer to. Including the below connectors, you can [Maven Repository: com.amazonaws:aws-java-sdk-redshift](https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-redshift) -### Apache Hive +### Apache Hive @@ -507,12 +507,11 @@ Here are some examples you can refer to. Including the below connectors, you can hive_password - hive.proxy.user - true or false + default.proxy.user.property + Example value: hive.server2.proxy.user + -Connection to Hive JDBC with a proxy user can be disabled with `hive.proxy.user` property (set to true by default) - [Apache Hive 1 JDBC Driver Docs](https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC) [Apache Hive 2 JDBC Driver Docs](https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC) @@ -534,6 +533,26 @@ Connection to Hive JDBC with a proxy user can be disabled with `hive.proxy.user` [Maven Repository : org.apache.hive:hive-jdbc](https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc) +##### Impersonation +When Zeppelin server is running with authentication enabled, then the interpreter can utilize Hive's user proxy feature i.e. send extra parameter for creating and running a session ("hive.server2.proxy.user=": "${loggedInUser}"). This is particularly useful when multiple users are sharing a notebooks. + +To enable this set following: + - `zeppelin.jdbc.auth.type` as `SIMPLE` or `KERBEROS` (if required) in the interpreter setting. + - `${prefix}.proxy.user.property` as `hive.server2.proxy.user` + Example configuration + + *Properties* + + | name | value | + |:------------------------- |:--------------------------------------------------------------------------------------------------| + | hive.driver | org.apache.hive.jdbc.HiveDriver | + | hive.password | | + | hive.url | jdbc:hive2://hive-server-host:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2 | + | hive.proxy.user.property | hive.proxy.user.property | + | zeppelin.jdbc.auth.type | SIMPLE | + + + ### Apache Phoenix Phoenix supports `thick` and `thin` connection types: diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java index cc2c55b0abf..e4040296b2d 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java @@ -26,7 +26,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.Set; @@ -179,10 +178,6 @@ public void open() { } logger.debug("JDBC PropretiesMap: {}", basePropretiesMap); - if (!isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) { - JDBCSecurityImpl.createSecureConfiguration(property); - } - setMaxLineResults(); } @@ -358,36 +353,25 @@ public Connection getConnection(String propertyKey, InterpreterContext interpret } else { UserGroupInformation.AuthenticationMethod authType = JDBCSecurityImpl.getAuthtype(property); + final String connectionUrl = appendProxyUserToURL(url, user, propertyKey); + + JDBCSecurityImpl.createSecureConfiguration(property, authType); switch (authType) { case KERBEROS: if (user == null || "false".equalsIgnoreCase( - property.getProperty("zeppelin.jdbc.auth.kerberos.proxy.enable"))) { - connection = getConnectionFromPool(url, user, propertyKey, properties); + property.getProperty("zeppelin.jdbc.auth.kerberos.proxy.enable"))) { + connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties); } else { - if (url.trim().startsWith("jdbc:hive")) { - StringBuilder connectionUrl = new StringBuilder(url); - Integer lastIndexOfUrl = connectionUrl.indexOf("?"); - if (lastIndexOfUrl == -1) { - lastIndexOfUrl = connectionUrl.length(); - } - boolean hasProxyUser = property.containsKey("hive.proxy.user"); - if (!hasProxyUser || !property.getProperty("hive.proxy.user").equals("false")){ - logger.debug("Using hive proxy user"); - connectionUrl.insert(lastIndexOfUrl, ";hive.server2.proxy.user=" + user + ";"); - } - connection = getConnectionFromPool(connectionUrl.toString(), - user, propertyKey, properties); + if (basePropretiesMap.get(propertyKey).containsKey("proxy.user.property")) { + connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties); } else { UserGroupInformation ugi = null; try { ugi = UserGroupInformation.createProxyUser( - user, UserGroupInformation.getCurrentUser()); + user, UserGroupInformation.getCurrentUser()); } catch (Exception e) { logger.error("Error in getCurrentUser", e); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(e.getMessage()).append("\n"); - stringBuilder.append(e.getCause()); - throw new InterpreterException(stringBuilder.toString()); + throw new InterpreterException("Error in getCurrentUser", e); } final String poolKey = propertyKey; @@ -395,28 +379,48 @@ public Connection getConnection(String propertyKey, InterpreterContext interpret connection = ugi.doAs(new PrivilegedExceptionAction() { @Override public Connection run() throws Exception { - return getConnectionFromPool(url, user, poolKey, properties); + return getConnectionFromPool(connectionUrl, user, poolKey, properties); } }); } catch (Exception e) { logger.error("Error in doAs", e); - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(e.getMessage()).append("\n"); - stringBuilder.append(e.getCause()); - throw new InterpreterException(stringBuilder.toString()); + throw new InterpreterException("Error in doAs", e); } } } break; default: - connection = getConnectionFromPool(url, user, propertyKey, properties); + connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties); } } return connection; } + private String appendProxyUserToURL(String url, String user, String propertyKey) { + StringBuilder connectionUrl = new StringBuilder(url); + + if (user != null && !user.equals("anonymous") && + basePropretiesMap.get(propertyKey).containsKey("proxy.user.property")) { + + Integer lastIndexOfUrl = connectionUrl.indexOf("?"); + if (lastIndexOfUrl == -1) { + lastIndexOfUrl = connectionUrl.length(); + } + logger.info("Using proxy user as :" + user); + logger.info("Using proxy property for user as :" + + basePropretiesMap.get(propertyKey).getProperty("proxy.user.property")); + connectionUrl.insert(lastIndexOfUrl, ";" + + basePropretiesMap.get(propertyKey).getProperty("proxy.user.property") + "=" + user + ";"); + } else if (user != null && !user.equals("anonymous") && url.contains("hive")) { + logger.warn("User impersonation for hive has changed please refer: http://zeppelin.apache" + + ".org/docs/latest/interpreter/jdbc.html#apache-hive"); + } + + return connectionUrl.toString(); + } + private String getPassword(Properties properties) throws IOException { if (isNotEmpty(properties.getProperty(PASSWORD_KEY))) { return properties.getProperty(PASSWORD_KEY); diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/security/JDBCSecurityImpl.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/security/JDBCSecurityImpl.java index 32a7990ff2f..25959e1a810 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/security/JDBCSecurityImpl.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/security/JDBCSecurityImpl.java @@ -38,9 +38,8 @@ public class JDBCSecurityImpl { /*** * @param properties */ - public static void createSecureConfiguration(Properties properties) { - AuthenticationMethod authType = getAuthtype(properties); - + public static void createSecureConfiguration(Properties properties, + AuthenticationMethod authType) { switch (authType) { case KERBEROS: Configuration conf = new diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterException.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterException.java index 30c1c0aae08..ebd184ecfbd 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterException.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterException.java @@ -31,4 +31,8 @@ public InterpreterException(String m) { super(m); } + public InterpreterException(String msg, Throwable t) { + super(msg, t); + } + }