Updated Branches:
refs/heads/db_policy_store 5de5202e3 -> 23fb569fb
SENTRY-103: Restrict connect to Sentry Service (Shreepadma via Brock)
Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/23fb569f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/23fb569f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/23fb569f
Branch: refs/heads/db_policy_store
Commit: 23fb569fbd87a61e64d90f5813c06979911ba40c
Parents: 5de5202
Author: Brock Noland <brock@cloudera.com>
Authored: Fri Jan 31 16:51:44 2014 -0600
Committer: Brock Noland <brock@cloudera.com>
Committed: Fri Jan 31 16:51:44 2014 -0600
----------------------------------------------------------------------
.../thrift/ConnectionDeniedException.java | 39 +++++++
.../provider/db/service/thrift/Constants.java | 3 +-
.../provider/db/service/thrift/GSSCallback.java | 102 +++++++++++++++++++
.../db/service/thrift/SentryService.java | 36 +++----
.../thrift/SentryServiceIntegrationBase.java | 40 +++++---
.../thrift/TestSentryServiceFailureCase.java | 46 +++++++++
.../thrift/TestSentryServiceIntegration.java | 3 +-
.../e2e/hive/TestPrivilegesAtTableScope.java | 2 +-
8 files changed, 237 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/ConnectionDeniedException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/ConnectionDeniedException.java
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/ConnectionDeniedException.java
new file mode 100644
index 0000000..c09a61c
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/ConnectionDeniedException.java
@@ -0,0 +1,39 @@
+/**
+ * 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.sentry.provider.db.service.thrift;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class ConnectionDeniedException extends UnsupportedCallbackException {
+
+ private static final long serialVersionUID = 653174214903923178L;
+ private String message;
+ private String connectionPrincipal;
+
+ public ConnectionDeniedException(Callback callback, String message, String connectionPrincipal)
{
+ super(callback, message);
+ this.message = message;
+ this.connectionPrincipal = connectionPrincipal;
+
+ }
+
+ public String getConnectionPrincipal() {
+ return connectionPrincipal;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/Constants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/Constants.java
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/Constants.java
index cf14cd0..62f7e4e 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/Constants.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/Constants.java
@@ -50,6 +50,7 @@ public class Constants {
public static final int RPC_MAX_THREADS_DEFAULT = 500;
public static final String RPC_MIN_THREADS = "sentry.service.server-min-threads";
public static final int RPC_MIN_THREADS_DEFAULT = 10;
+ public static final String ALLOW_CONNECT = "sentry.service.allow.connect";
}
public static class ClientConfig {
public static final ImmutableMap<String, String> SASL_PROPERTIES = Constants.SASL_PROPERTIES;
@@ -57,7 +58,7 @@ public class Constants {
public static final int SERVER_RPC_PORT_DEFAULT = ServerConfig.RPC_PORT_DEFAULT;
public static final String SERVER_RPC_ADDRESS = "sentry.service.client.server.rpc-address";
public static final String SERVER_RPC_CONN_TIMEOUT = "sentry.service.client.server.rpc-connection-timeout";
- public static final int SERVER_RPC_CONN_TIMEOUT_DEFAULT = 20000;
+ public static final int SERVER_RPC_CONN_TIMEOUT_DEFAULT = 200000;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/GSSCallback.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/GSSCallback.java
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/GSSCallback.java
new file mode 100644
index 0000000..c28311c
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/GSSCallback.java
@@ -0,0 +1,102 @@
+/**
+ * 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.sentry.provider.db.service.thrift;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.SaslRpcServer;
+
+public class GSSCallback extends SaslRpcServer.SaslGssCallbackHandler {
+
+ private final Configuration conf;
+ public GSSCallback(Configuration conf) {
+ super();
+ this.conf = conf;
+ }
+
+ boolean comparePrincipals(String principal1, String principal2) {
+ String[] principalParts1 = SaslRpcServer.splitKerberosName(principal1);
+ String[] principalParts2 = SaslRpcServer.splitKerberosName(principal2);
+ if (principalParts1.length == 0 || principalParts2.length == 0) {
+ return false;
+ }
+ if (principalParts1.length == principalParts2.length) {
+ for (int i=0; i < principalParts1.length; i++) {
+ if (!principalParts1[i].equals(principalParts2[i])) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ boolean allowConnect(String principal) {
+ String allowedPrincipals = conf.get("sentry.service.allow.connect");
+ if (allowedPrincipals == null) {
+ return false;
+ }
+ List<String> items = Arrays.asList(allowedPrincipals.split("\\s*,\\s*"));
+ for (String item:items) {
+ if(comparePrincipals(item, principal)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks)
+ throws UnsupportedCallbackException, ConnectionDeniedException {
+ AuthorizeCallback ac = null;
+ for (Callback callback : callbacks) {
+ if (callback instanceof AuthorizeCallback) {
+ ac = (AuthorizeCallback) callback;
+ } else {
+ throw new UnsupportedCallbackException(callback,
+ "Unrecognized SASL GSSAPI Callback");
+ }
+ }
+ if (ac != null) {
+ String authid = ac.getAuthenticationID();
+ String authzid = ac.getAuthorizationID();
+
+ if (allowConnect(authid)) {
+ if (authid.equals(authzid)) {
+ ac.setAuthorized(true);
+ } else {
+ ac.setAuthorized(false);
+ }
+ if (ac.isAuthorized()) {
+ ac.setAuthorizedID(authzid);
+ }
+ } else {
+ throw new ConnectionDeniedException(ac,
+ "Connection to sentry service denied due to lack
of client credentials",
+ authid);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryService.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryService.java
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryService.java
index c106568..66ed637 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryService.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryService.java
@@ -81,23 +81,23 @@ public class SentryService implements Runnable {
port = findFreePort();
}
this.address = NetUtils.createSocketAddr(conf.
- get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT),
- port);
+ get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT),
+ port);
LOGGER.info("Configured on address " + address);
maxThreads = conf.getInt(ServerConfig.RPC_MAX_THREADS,
- ServerConfig.RPC_MAX_THREADS_DEFAULT);
+ ServerConfig.RPC_MAX_THREADS_DEFAULT);
minThreads = conf.getInt(ServerConfig.RPC_MIN_THREADS,
- ServerConfig.RPC_MIN_THREADS_DEFAULT);
+ ServerConfig.RPC_MIN_THREADS_DEFAULT);
principal = Preconditions.checkNotNull(conf.get(ServerConfig.PRINCIPAL),
- ServerConfig.PRINCIPAL + " is required");
+ ServerConfig.PRINCIPAL + " is required");
principalParts = SaslRpcServer.splitKerberosName(principal);
Preconditions.checkArgument(principalParts.length == 3,
- "Kerberos principal should have 3 parts: " + principal);
+ "Kerberos principal should have 3 parts: " + principal);
keytab = Preconditions.checkNotNull(conf.get(ServerConfig.KEY_TAB),
- ServerConfig.KEY_TAB + " is required");
+ ServerConfig.KEY_TAB + " is required");
File keytabFile = new File(keytab);
Preconditions.checkState(keytabFile.isFile() && keytabFile.canRead(),
- "Keytab " + keytab + " does not exist or is not readable.");
+ "Keytab " + keytab + " does not exist or is not readable.");
serviceExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
private int count = 0;
@Override
@@ -113,10 +113,10 @@ public class SentryService implements Runnable {
LoginContext loginContext = null;
try {
Subject subject = new Subject(false, Sets.newHashSet(
- new KerberosPrincipal(principal)), new HashSet<Object>(),
- new HashSet<Object>());
+ new KerberosPrincipal(principal)), new HashSet<Object>(),
+ new HashSet<Object>());
loginContext = new LoginContext("", subject, null,
- KerberosConfiguration.createClientConfig(principal, new File(keytab)));
+ KerberosConfiguration.createClientConfig(principal,
new File(keytab)));
loginContext.login();
subject = loginContext.getSubject();
Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
@@ -124,15 +124,15 @@ public class SentryService implements Runnable {
public Void run() throws Exception {
SentryServiceHandler sentryServiceHandler = new SentryServiceHandler("sentry-policy-service",
null);
TProcessor processor =
- new SentryThriftService.Processor<SentryThriftService.Iface>(sentryServiceHandler);
+ new SentryThriftService.Processor<SentryThriftService.Iface>(sentryServiceHandler);
TServerTransport serverTransport = new TServerSocket(address);
TSaslServerTransport.Factory saslTransportFactory = new TSaslServerTransport.Factory();
saslTransportFactory.addServerDefinition(
- AuthMethod.KERBEROS.getMechanismName(),
- principalParts[0],
- principalParts[1],
- ServerConfig.SASL_PROPERTIES,
- new SaslRpcServer.SaslGssCallbackHandler());
+ AuthMethod.KERBEROS.getMechanismName(),
+ principalParts[0],
+ principalParts[1],
+ ServerConfig.SASL_PROPERTIES,
+ new GSSCallback(conf));
TThreadPoolServer.Args args = new TThreadPoolServer.Args(serverTransport)
.processor(processor)
.transportFactory(saslTransportFactory)
@@ -210,7 +210,7 @@ public class SentryService implements Runnable {
File configFile = null;
if (args.length != 2 || !args[0].equalsIgnoreCase(Constants.ServerArgs.CONFIG_FILE))
{
throw new IllegalArgumentException("Usage: " + Constants.ServerArgs.CONFIG_FILE
- + " path/to/sentry-service.xml");
+ + " path/to/sentry-service.xml");
} else if(!((configFile = new File(args[1])).isFile() && configFile.canRead()))
{
throw new IllegalArgumentException("Cannot read configuration file " + configFile);
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
index b7c44a4..e94eb78 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
@@ -65,39 +65,54 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc
protected File clientKeytab;
protected Subject clientSubject;
protected LoginContext clientLoginContext;
+ protected final Configuration conf = new Configuration(false);
@Before
public void setup() throws Exception {
beforeSetup();
+ setupConf();
+ startSentryService();
+ connectToSentryService();
+ afterSetup();
+ }
+
+ public void startSentryService() throws Exception {
+ server.start();
+ final long start = System.currentTimeMillis();
+ while(!server.isRunning()) {
+ Thread.sleep(1000);
+ if(System.currentTimeMillis() - start > 60000L) {
+ throw new TimeoutException("Server did not start after 60 seconds");
+ }
+ }
+ }
+
+ public void setupConf() throws Exception {
kdc = getKdc();
kdcWorkDir = getWorkDir();
serverKeytab = new File(kdcWorkDir, "server.keytab");
clientKeytab = new File(kdcWorkDir, "client.keytab");
kdc.createPrincipal(serverKeytab, SERVER_PRINCIPAL);
kdc.createPrincipal(clientKeytab, CLIENT_PRINCIPAL);
- final Configuration conf = new Configuration(false);
+
conf.set(ServerConfig.PRINCIPAL, SERVER_KERBEROS_NAME);
conf.set(ServerConfig.KEY_TAB, serverKeytab.getPath());
conf.set(ServerConfig.RPC_ADDRESS, SERVER_HOST);
conf.set(ServerConfig.RPC_PORT, String.valueOf(0));
+ conf.set(ServerConfig.ALLOW_CONNECT, CLIENT_KERBEROS_NAME);
server = new SentryServiceFactory().create(conf);
conf.set(ClientConfig.SERVER_RPC_ADDRESS, server.getAddress().getHostString());
conf.set(ClientConfig.SERVER_RPC_PORT, String.valueOf(server.getAddress().getPort()));
- server.start();
- final long start = System.currentTimeMillis();
- while(!server.isRunning()) {
- Thread.sleep(1000);
- if(System.currentTimeMillis() - start > 60000L) {
- throw new TimeoutException("Server did not start after 60 seconds");
- }
- }
+ }
+
+ public void connectToSentryService() throws Exception {
// The client should already be logged in when running in hive/impala/solr
// therefore we must manually login in the integration tests
clientSubject = new Subject(false, Sets.newHashSet(
- new KerberosPrincipal(CLIENT_KERBEROS_NAME)), new HashSet<Object>(),
- new HashSet<Object>());
+ new KerberosPrincipal(CLIENT_KERBEROS_NAME)), new HashSet<Object>(),
+ new HashSet<Object>());
clientLoginContext = new LoginContext("", clientSubject, null,
- KerberosConfiguration.createClientConfig(CLIENT_KERBEROS_NAME, clientKeytab));
+ KerberosConfiguration.createClientConfig(CLIENT_KERBEROS_NAME,
clientKeytab));
clientLoginContext.login();
clientSubject = clientLoginContext.getSubject();
client = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SentryServiceClient>()
{
@@ -106,7 +121,6 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc
return new SentryServiceClientFactory().create(conf);
}
});
- afterSetup();
}
@After
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
new file mode 100644
index 0000000..063a5b0
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
@@ -0,0 +1,46 @@
+/**
+ * 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.sentry.provider.db.service.thrift;
+
+import org.apache.sentry.provider.db.service.thrift.Constants.ServerConfig;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.security.PrivilegedActionException;
+
+public class TestSentryServiceFailureCase extends SentryServiceIntegrationBase {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryServiceFailureCase.class);
+
+ @Before @Override
+ public void setup() throws Exception {
+ beforeSetup();
+ setupConf();
+ conf.set(ServerConfig.ALLOW_CONNECT, "");
+ startSentryService();
+ afterSetup();
+ }
+
+ @Test(expected = PrivilegedActionException.class)
+ public void testClientServerConnectionFailure() throws Exception {
+ connectToSentryService();
+ Assert.fail("Failed to receive Exception");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
index 74704e2..3988229 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
@@ -19,6 +19,7 @@
package org.apache.sentry.provider.db.service.thrift;
import java.util.HashSet;
+import org.apache.sentry.provider.db.service.thrift.Constants.ServerConfig;
import org.apache.sentry.service.api.TCreateSentryRoleRequest;
import org.apache.sentry.service.api.TCreateSentryRoleResponse;
import org.apache.sentry.service.api.TSentryPrivilege;
@@ -50,4 +51,4 @@ public class TestSentryServiceIntegration extends SentryServiceIntegrationBase
{
+ ":\nstack:" + resp.getStatus().getStack());
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/23fb569f/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
index 0198a6f..c267ea6 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
@@ -200,7 +200,7 @@ public class TestPrivilegesAtTableScope extends AbstractTestWithStaticConfigurat
statement = context.createStatement(connection);
statement.execute("USE DB_1");
// test user can execute insert on table
- statement.executeQuery("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+ statement.execute("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
// negative test: user can't query table
try {
|