mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
ZEPPELIN-1935 Add jceks stored password support for jdbc interpreter
This commit is contained in:
parent
d96a149138
commit
d41d56c70d
3 changed files with 112 additions and 12 deletions
|
|
@ -159,6 +159,14 @@ There are more JDBC interpreter properties you can specify like below.
|
|||
<td>zeppelin.jdbc.keytab.location</td>
|
||||
<td>The path to the keytab file</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>default.jceks.file</td>
|
||||
<td>jceks store path (e.g: jceks://file/tmp/zeppelin.jceks)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>default.jceks.credentialKey</td>
|
||||
<td>jceks credential key</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
You can also add more properties by using this [method](http://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html#getConnection%28java.lang.String,%20java.util.Properties%29).
|
||||
|
|
|
|||
54
jdbc/pom.xml
54
jdbc/pom.xml
|
|
@ -39,6 +39,7 @@
|
|||
<hadoop.common.version>2.7.2</hadoop.common.version>
|
||||
<h2.version>1.4.190</h2.version>
|
||||
<commons.dbcp2.version>2.0.1</commons.dbcp2.version>
|
||||
<hadoop-common.version>2.6.0</hadoop-common.version>
|
||||
|
||||
<!--test library versions-->
|
||||
<mockrunner.jdbc.version>1.0.8</mockrunner.jdbc.version>
|
||||
|
|
@ -117,6 +118,59 @@
|
|||
<version>${mockrunner.jdbc.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.hadoop</groupId>
|
||||
<artifactId>hadoop-common</artifactId>
|
||||
<version>${hadoop-common.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
</exclusion>
|
||||
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.avro</groupId>
|
||||
<artifactId>avro</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.jackrabbit</groupId>
|
||||
<artifactId>jackrabbit-webdav</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-httpclient</groupId>
|
||||
<artifactId>commons-httpclient</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
package org.apache.zeppelin.jdbc;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.containsIgnoreCase;
|
||||
import static org.apache.commons.lang.StringUtils.isEmpty;
|
||||
import static org.apache.commons.lang.StringUtils.isNotEmpty;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
|
|
@ -26,10 +28,12 @@ import org.apache.commons.dbcp2.ConnectionFactory;
|
|||
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
|
||||
import org.apache.commons.dbcp2.PoolableConnectionFactory;
|
||||
import org.apache.commons.dbcp2.PoolingDriver;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.pool2.ObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.security.alias.CredentialProvider;
|
||||
import org.apache.hadoop.security.alias.CredentialProviderFactory;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
|
|
@ -76,8 +80,6 @@ public class JDBCInterpreter extends Interpreter {
|
|||
private Logger logger = LoggerFactory.getLogger(JDBCInterpreter.class);
|
||||
|
||||
static final String INTERPRETER_NAME = "jdbc";
|
||||
static final String JDBC_DEFAULT_USER_KEY = "default.user";
|
||||
static final String JDBC_DEFAULT_PASSWORD_KEY = "default.password";
|
||||
static final String COMMON_KEY = "common";
|
||||
static final String MAX_LINE_KEY = "max_count";
|
||||
static final int MAX_LINE_DEFAULT = 1000;
|
||||
|
|
@ -87,6 +89,8 @@ public class JDBCInterpreter extends Interpreter {
|
|||
static final String URL_KEY = "url";
|
||||
static final String USER_KEY = "user";
|
||||
static final String PASSWORD_KEY = "password";
|
||||
static final String JDBC_JCEKS_FILE = "jceks.file";
|
||||
static final String JDBC_JCEKS_CREDENTIAL_KEY = "jceks.credentialKey";
|
||||
static final String DOT = ".";
|
||||
|
||||
private static final char WHITESPACE = ' ';
|
||||
|
|
@ -94,7 +98,6 @@ public class JDBCInterpreter extends Interpreter {
|
|||
private static final char TAB = '\t';
|
||||
private static final String TABLE_MAGIC_TAG = "%table ";
|
||||
private static final String EXPLAIN_PREDICATE = "EXPLAIN ";
|
||||
private static final String UPDATE_COUNT_HEADER = "Update Count";
|
||||
|
||||
static final String COMMON_MAX_LINE = COMMON_KEY + DOT + MAX_LINE_KEY;
|
||||
|
||||
|
|
@ -171,7 +174,7 @@ public class JDBCInterpreter extends Interpreter {
|
|||
}
|
||||
logger.debug("JDBC PropretiesMap: {}", basePropretiesMap);
|
||||
|
||||
if (!StringUtils.isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) {
|
||||
if (!isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) {
|
||||
JDBCSecurityImpl.createSecureConfiguration(property);
|
||||
}
|
||||
for (String propertyKey : basePropretiesMap.keySet()) {
|
||||
|
|
@ -250,9 +253,9 @@ public class JDBCInterpreter extends Interpreter {
|
|||
return driverName.toString();
|
||||
}
|
||||
|
||||
private boolean existAccountInBaseProperty() {
|
||||
return property.containsKey(JDBC_DEFAULT_USER_KEY) &&
|
||||
property.containsKey(JDBC_DEFAULT_PASSWORD_KEY);
|
||||
private boolean existAccountInBaseProperty(String propertyKey) {
|
||||
return basePropretiesMap.get(propertyKey).containsKey(USER_KEY) &&
|
||||
basePropretiesMap.get(propertyKey).containsKey(PASSWORD_KEY);
|
||||
}
|
||||
|
||||
private UsernamePassword getUsernamePassword(InterpreterContext interpreterContext,
|
||||
|
|
@ -284,15 +287,22 @@ public class JDBCInterpreter extends Interpreter {
|
|||
}
|
||||
|
||||
private void setUserProperty(String propertyKey, InterpreterContext interpreterContext)
|
||||
throws SQLException {
|
||||
throws SQLException, IOException {
|
||||
|
||||
String user = interpreterContext.getAuthenticationInfo().getUser();
|
||||
|
||||
JDBCUserConfigurations jdbcUserConfigurations =
|
||||
getJDBCConfiguration(user);
|
||||
if (basePropretiesMap.get(propertyKey).containsKey(USER_KEY) &&
|
||||
!basePropretiesMap.get(propertyKey).getProperty(USER_KEY).isEmpty()) {
|
||||
String password = getPassword(basePropretiesMap.get(propertyKey));
|
||||
if (!isEmpty(password)) {
|
||||
basePropretiesMap.get(propertyKey).setProperty(PASSWORD_KEY, password);
|
||||
}
|
||||
}
|
||||
jdbcUserConfigurations.setPropertyMap(propertyKey, basePropretiesMap.get(propertyKey));
|
||||
|
||||
if (existAccountInBaseProperty()) {
|
||||
if (existAccountInBaseProperty(propertyKey)) {
|
||||
return;
|
||||
}
|
||||
jdbcUserConfigurations.cleanUserProperty(propertyKey);
|
||||
|
|
@ -333,7 +343,7 @@ public class JDBCInterpreter extends Interpreter {
|
|||
}
|
||||
|
||||
public Connection getConnection(String propertyKey, InterpreterContext interpreterContext)
|
||||
throws ClassNotFoundException, SQLException, InterpreterException {
|
||||
throws ClassNotFoundException, SQLException, InterpreterException, IOException {
|
||||
final String user = interpreterContext.getAuthenticationInfo().getUser();
|
||||
Connection connection;
|
||||
if (propertyKey == null || basePropretiesMap.get(propertyKey) == null) {
|
||||
|
|
@ -346,7 +356,7 @@ public class JDBCInterpreter extends Interpreter {
|
|||
final Properties properties = jdbcUserConfigurations.getPropertyMap(propertyKey);
|
||||
final String url = properties.getProperty(URL_KEY);
|
||||
|
||||
if (StringUtils.isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) {
|
||||
if (isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) {
|
||||
connection = getConnectionFromPool(url, user, propertyKey, properties);
|
||||
} else {
|
||||
UserGroupInformation.AuthenticationMethod authType = JDBCSecurityImpl.getAuthtype(property);
|
||||
|
|
@ -399,6 +409,34 @@ public class JDBCInterpreter extends Interpreter {
|
|||
return connection;
|
||||
}
|
||||
|
||||
private String getPassword(Properties properties) throws IOException {
|
||||
if (isNotEmpty(properties.getProperty(PASSWORD_KEY))) {
|
||||
return properties.getProperty(PASSWORD_KEY);
|
||||
} else if (isNotEmpty(properties.getProperty(JDBC_JCEKS_FILE))
|
||||
&& isNotEmpty(properties.getProperty(JDBC_JCEKS_CREDENTIAL_KEY))) {
|
||||
try {
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
|
||||
properties.getProperty(JDBC_JCEKS_FILE));
|
||||
CredentialProvider provider = CredentialProviderFactory.getProviders(configuration).get(0);
|
||||
CredentialProvider.CredentialEntry credEntry =
|
||||
provider.getCredentialEntry(properties.getProperty(JDBC_JCEKS_CREDENTIAL_KEY));
|
||||
if (credEntry != null) {
|
||||
return new String(credEntry.getCredential());
|
||||
} else {
|
||||
throw new InterpreterException("Failed to retrieve password from JCEKS from key: "
|
||||
+ properties.getProperty(JDBC_JCEKS_CREDENTIAL_KEY));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to retrieve password from JCEKS", e);
|
||||
logger.error("For file: " + properties.getProperty(JDBC_JCEKS_FILE));
|
||||
logger.error("For key: " + properties.getProperty(JDBC_JCEKS_CREDENTIAL_KEY));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getResults(ResultSet resultSet, boolean isTableType)
|
||||
throws SQLException {
|
||||
ResultSetMetaData md = resultSet.getMetaData();
|
||||
|
|
|
|||
Loading…
Reference in a new issue