You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/06/08 19:44:04 UTC
git commit: PHOENIX-19 Enhance JDBC connection of Phoenix to support
connecting to a Secure HBase cluster (Anil Gupta)
Repository: phoenix
Updated Branches:
refs/heads/4.0 2d9347e0b -> 3ef7df14c
PHOENIX-19 Enhance JDBC connection of Phoenix to support connecting to a Secure HBase cluster (Anil Gupta)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/3ef7df14
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/3ef7df14
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/3ef7df14
Branch: refs/heads/4.0
Commit: 3ef7df14ce125996ce77d1bf9e4e06abba988883
Parents: 2d9347e
Author: James Taylor <jt...@salesforce.com>
Authored: Sun Jun 8 10:45:38 2014 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Sun Jun 8 10:45:38 2014 -0700
----------------------------------------------------------------------
.../phoenix/jdbc/PhoenixEmbeddedDriver.java | 100 ++++++++++++++++---
.../query/ConnectionQueryServicesImpl.java | 16 ++-
.../org/apache/phoenix/query/QueryServices.java | 3 +
.../phoenix/jdbc/PhoenixEmbeddedDriverTest.java | 9 ++
4 files changed, 112 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ef7df14/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
index 8cfe3c2..10c24b8 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
@@ -169,7 +169,7 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
StringTokenizer tokenizer = new StringTokenizer(url == null ? "" : url.substring(PhoenixRuntime.JDBC_PROTOCOL.length()),DELIMITERS, true);
int i = 0;
boolean isMalformedUrl = false;
- String[] tokens = new String[3];
+ String[] tokens = new String[5];
String token = null;
while (tokenizer.hasMoreTokens() && !(token=tokenizer.nextToken()).equals(TERMINATOR) && tokenizer.hasMoreTokens() && i < tokens.length) {
token = tokenizer.nextToken();
@@ -188,14 +188,41 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
try {
port = Integer.parseInt(tokens[1]);
isMalformedUrl = port < 0;
+ if(i == 4){
+ if(!tokens[2].endsWith(".keytab")){
+ isMalformedUrl = true;
+ }
+ tokens[4] = tokens[3];
+ tokens[3] = tokens[2];
+ tokens[2] = null;
+ }
} catch (NumberFormatException e) {
// If we have 3 tokens, then the second one must be a port.
// If we only have 2 tokens, the second one might be the root node:
// Assume that is the case if we get a NumberFormatException
- if (! (isMalformedUrl = i == 3) ) {
+ if (!tokens[1].startsWith("/")) {
+ isMalformedUrl = true;
+ }
+ if (i == 2) {
+ tokens[4] = null;
+ tokens[3] = null;
+ tokens[2] = tokens[1];
+ tokens[1] = null;
+ } else if (i == 3) {
+ tokens[4] = tokens[2];
+ tokens[3] = tokens[1];
+ tokens[2] = null;
+ tokens[1] = null;
+ } else if (i == 4) {
+ tokens[4] = tokens[3];
+ tokens[3] = tokens[2];
+ tokens[2] = tokens[1];
+ tokens[1] = null;
+ } else if (i == 5) {
+ tokens[4] = tokens[3];
+ tokens[3] = tokens[2];
tokens[2] = tokens[1];
}
-
}
}
}
@@ -203,13 +230,15 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
throw new SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL)
.setMessage(url).build().buildException();
}
- return new ConnectionInfo(tokens[0],port,tokens[2]);
+ return new ConnectionInfo(tokens[0],port,tokens[2], tokens[3], tokens[4]);
}
public ConnectionInfo normalize(ReadOnlyProps props) throws SQLException {
String zookeeperQuorum = this.getZookeeperQuorum();
Integer port = this.getPort();
String rootNode = this.getRootNode();
+ String keytab = this.getKeytab();
+ String principal = this.getPrincipal();
// Normalize connInfo so that a url explicitly specifying versus implicitly inheriting
// the default values will both share the same ConnectionQueryServices.
if (zookeeperQuorum == null) {
@@ -244,24 +273,45 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
throw new SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL)
.setMessage("Root node may not be specified when using the connectionless url \"" + this.toString() + "\"").build().buildException();
}
- return new ConnectionInfo(zookeeperQuorum, port, rootNode);
+ if(keytab == null){
+ if (!isConnectionless) {
+ keytab = props.get(QueryServices.HBASE_CLIENT_KEYTAB);
+ }
+ }
+ if(principal == null){
+ if (!isConnectionless) {
+ principal = props.get(QueryServices.HBASE_CLIENT_PRINCIPAL);
+ }
+ }
+ if (keytab == null || keytab.equals("")) return new ConnectionInfo(zookeeperQuorum,
+ port, rootNode);
+ else return new ConnectionInfo(zookeeperQuorum, port, rootNode, keytab, principal);
}
private final Integer port;
private final String rootNode;
private final String zookeeperQuorum;
private final boolean isConnectionless;
+ private final String principal;
+ private final String keytab;
// used for testing
- ConnectionInfo(String zookeeperQuorum, Integer port, String rootNode) {
+ ConnectionInfo(String zookeeperQuorum, Integer port, String rootNode, String keytab, String principal) {
this.zookeeperQuorum = zookeeperQuorum;
this.port = port;
this.rootNode = rootNode;
this.isConnectionless = PhoenixRuntime.CONNECTIONLESS.equals(zookeeperQuorum);
+ this.principal = principal;
+ this.keytab = keytab;
+ }
+
+ // used for testing
+ ConnectionInfo(String zookeeperQuorum, Integer port, String rootNode) {
+ this(zookeeperQuorum, port, rootNode, null, null);
}
public ReadOnlyProps asProps() {
- Map<String,String> connectionProps = Maps.newHashMapWithExpectedSize(3);
+ Map<String, String> connectionProps = Maps.newHashMapWithExpectedSize(3);
if (getZookeeperQuorum() != null) {
connectionProps.put(QueryServices.ZOOKEEPER_QUARUM_ATTRIB, getZookeeperQuorum());
}
@@ -271,7 +321,14 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
if (getRootNode() != null) {
connectionProps.put(QueryServices.ZOOKEEPER_ROOT_NODE_ATTRIB, getRootNode());
}
- return connectionProps.isEmpty() ? ReadOnlyProps.EMPTY_PROPS : new ReadOnlyProps(connectionProps.entrySet().iterator());
+ if (getKeytab() != null) {
+ connectionProps.put(QueryServices.HBASE_CLIENT_KEYTAB, getKeytab());
+ }
+ if (getPrincipal() != null) {
+ connectionProps.put(QueryServices.HBASE_CLIENT_PRINCIPAL, getPrincipal());
+ }
+ return connectionProps.isEmpty() ? ReadOnlyProps.EMPTY_PROPS : new ReadOnlyProps(
+ connectionProps.entrySet().iterator());
}
public boolean isConnectionless() {
@@ -289,6 +346,14 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
public String getRootNode() {
return rootNode;
}
+
+ public String getKeytab() {
+ return keytab;
+ }
+
+ public String getPrincipal() {
+ return principal;
+ }
@Override
public int hashCode() {
@@ -297,6 +362,8 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
result = prime * result + ((zookeeperQuorum == null) ? 0 : zookeeperQuorum.hashCode());
result = prime * result + ((port == null) ? 0 : port.hashCode());
result = prime * result + ((rootNode == null) ? 0 : rootNode.hashCode());
+ result = prime * result + ((keytab == null) ? 0 : keytab.hashCode());
+ result = prime * result + ((principal == null) ? 0 : keytab.hashCode());
return result;
}
@@ -305,7 +372,7 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
- ConnectionInfo other = (ConnectionInfo)obj;
+ ConnectionInfo other = (ConnectionInfo) obj;
if (zookeeperQuorum == null) {
if (other.zookeeperQuorum != null) return false;
} else if (!zookeeperQuorum.equals(other.zookeeperQuorum)) return false;
@@ -315,13 +382,22 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni
if (rootNode == null) {
if (other.rootNode != null) return false;
} else if (!rootNode.equals(other.rootNode)) return false;
+ if (keytab == null) {
+ if (other.keytab != null) return false;
+ } else if (!keytab.equals(other.keytab)) return false;
+ if (principal == null) {
+ if (other.principal != null) return false;
+ } else if (!principal.equals(other.principal)) return false;
return true;
}
@Override
- public String toString() {
- return zookeeperQuorum + (port == null ? "" : ":" + port) + (rootNode == null ? "" : ":" + rootNode);
- }
+ public String toString() {
+ return zookeeperQuorum + (port == null ? "" : ":" + port)
+ + (rootNode == null ? "" : ":" + rootNode)
+ + (keytab == null ? "" : ":" + keytab)
+ + (principal == null ? "" : ":" + principal);
+ }
}
public static boolean isTestUrl(String url) {
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ef7df14/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 912db88..716ba3d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -64,7 +64,6 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import com.google.protobuf.HBaseZeroCopyByteString;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.HColumnDescriptor;
@@ -89,10 +88,12 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
import org.apache.hadoop.hbase.ipc.ServerRpcController;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
+import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.VersionInfo;
import org.apache.hadoop.hbase.zookeeper.ZKConfig;
+import org.apache.hadoop.security.UserGroupInformation;
import org.apache.phoenix.compile.MutationPlan;
import org.apache.phoenix.coprocessor.GroupedAggregateRegionObserver;
import org.apache.phoenix.coprocessor.MetaDataEndpointImpl;
@@ -171,6 +172,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Closeables;
+import com.google.protobuf.HBaseZeroCopyByteString;
public class ConnectionQueryServicesImpl extends DelegateQueryServices implements ConnectionQueryServices {
@@ -252,6 +254,15 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
private void openConnection() throws SQLException {
try {
+ // check if we need to authenticate with kerberos
+ String clientKeytab = config.get(HBASE_CLIENT_KEYTAB);
+ String clientPrincipal = config.get(HBASE_CLIENT_PRINCIPAL);
+ if (clientKeytab != null && clientPrincipal != null) {
+ logger.info("Trying to connect to a secure cluster with keytab:" + clientKeytab);
+ UserGroupInformation.setConfiguration(config);
+ User.login(config, HBASE_CLIENT_KEYTAB, HBASE_CLIENT_PRINCIPAL, null);
+ logger.info("Successfull login to secure cluster!!");
+ }
this.connection = HBaseFactoryProvider.getHConnectionFactory().createConnection(this.config);
} catch (IOException e) {
throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ESTABLISH_CONNECTION)
@@ -388,7 +399,6 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
return childQueryService;
}
- @SuppressWarnings("deprecation")
@Override
public void clearTableRegionCache(byte[] tableName) throws SQLException {
connection.clearRegionCache(TableName.valueOf(tableName));
@@ -410,7 +420,6 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
List<HRegionLocation> locations = Lists.newArrayList();
byte[] currentKey = HConstants.EMPTY_START_ROW;
do {
- @SuppressWarnings("deprecation")
HRegionLocation regionLocation = connection.getRegionLocation(
TableName.valueOf(tableName), currentKey, reload);
locations.add(regionLocation);
@@ -945,7 +954,6 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
* Invoke meta data coprocessor with one retry if the key was found to not be in the regions
* (due to a table split)
*/
- @SuppressWarnings("deprecation")
private MetaDataMutationResult metaDataCoprocessorExec(byte[] tableKey,
Batch.Call<MetaDataService, MetaDataResponse> callable) throws SQLException {
try {
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ef7df14/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index 44ec932..9c751ba 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -44,6 +44,9 @@ public interface QueryServices extends SQLCloseable {
public static final String QUEUE_SIZE_ATTRIB = "phoenix.query.queueSize";
public static final String THREAD_TIMEOUT_MS_ATTRIB = "phoenix.query.timeoutMs";
public static final String SPOOL_THRESHOLD_BYTES_ATTRIB = "phoenix.query.spoolThresholdBytes";
+ public static final String HBASE_CLIENT_KEYTAB = "hbase.myclient.keytab";
+ public static final String HBASE_CLIENT_PRINCIPAL = "hbase.myclient.principal";
+
/**
* max size to spool the the result into
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3ef7df14/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java
index 23c7951..a9b09e5 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java
@@ -47,6 +47,10 @@ public class PhoenixEmbeddedDriverTest {
"jdbc:phoenix:v1,v2,v3:/hbase;test=true",
"jdbc:phoenix:v1,v2,v3:123:/hbase",
"jdbc:phoenix:v1,v2,v3:123:/hbase;test=false",
+ "jdbc:phoenix:v1,v2,v3:123:/hbase:/user.keytab:user/principal;test=false",
+ "jdbc:phoenix:v1,v2,v3:123:/user.keytab:user/principal;test=false",
+ "jdbc:phoenix:v1,v2,v3:/user.keytab:user/principal;test=false",
+ "jdbc:phoenix:v1,v2,v3:/hbase:/user.keytab:user/principal;test=false"
};
ConnectionInfo[] infos = new ConnectionInfo[] {
new ConnectionInfo(null,null,null),
@@ -65,6 +69,10 @@ public class PhoenixEmbeddedDriverTest {
new ConnectionInfo("v1,v2,v3",null,"/hbase"),
new ConnectionInfo("v1,v2,v3",123,"/hbase"),
new ConnectionInfo("v1,v2,v3",123,"/hbase"),
+ new ConnectionInfo("v1,v2,v3",123,"/hbase", "/user.keytab","user/principal" ),
+ new ConnectionInfo("v1,v2,v3",123, null, "/user.keytab","user/principal" ),
+ new ConnectionInfo("v1,v2,v3", null, null, "/user.keytab","user/principal" ),
+ new ConnectionInfo("v1,v2,v3",null,"/hbase", "/user.keytab","user/principal" )
};
assertEquals(urls.length,infos.length);
for (int i = 0; i < urls.length; i++) {
@@ -92,6 +100,7 @@ public class PhoenixEmbeddedDriverTest {
"jdbc:phoenix:v1,v2,v3:123a:/hbase;test=true",
"jdbc:phoenix:v1,v2,v3:123::/hbase",
"jdbc:phoenix:v1,v2,v3:123::/hbase;test=false",
+ "jdbc:phoenix:v1,v2,v3:123:/hbase:user;test=false"
};
for (String url : urls) {
try {