Repository: incubator-sentry Updated Branches: refs/heads/master fbf042e66 -> 63c134f36
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/GSSCallback.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/GSSCallback.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/GSSCallback.java index c4a0fd4..22f31cd 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/GSSCallback.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/GSSCallback.java @@ -26,6 +26,7 @@ import javax.security.sasl.AuthorizeCallback; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.SaslRpcServer; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; public class GSSCallback extends SaslRpcServer.SaslGssCallbackHandler { @@ -54,12 +55,12 @@ public class GSSCallback extends SaslRpcServer.SaslGssCallbackHandler { } boolean allowConnect(String principal) { - String allowedPrincipals = conf.get("sentry.service.allow.connect"); + String allowedPrincipals = conf.get(ServerConfig.ALLOW_CONNECT); if (allowedPrincipals == null) { return false; } List<String> items = Arrays.asList(allowedPrincipals.split("\\s*,\\s*")); - for (String item:items) { + for (String item : items) { if(comparePrincipals(item, principal)) { return true; } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java index fbb0eef..bebaf0d 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java @@ -52,6 +52,7 @@ import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.transport.TSaslServerTransport; import org.apache.thrift.transport.TServerSocket; import org.apache.thrift.transport.TServerTransport; +import org.apache.thrift.transport.TTransportFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,6 +72,7 @@ public class SentryService implements Runnable { private final InetSocketAddress address; private final int maxThreads; private final int minThreads; + private boolean kerberos; private final String principal; private final String[] principalParts; private final String keytab; @@ -90,20 +92,28 @@ public class SentryService implements Runnable { conf.get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT), port); LOGGER.info("Configured on address " + address); + kerberos = ServerConfig.SECURITY_MODE_KERBEROS.equalsIgnoreCase( + conf.get(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_KERBEROS).trim()); maxThreads = conf.getInt(ServerConfig.RPC_MAX_THREADS, ServerConfig.RPC_MAX_THREADS_DEFAULT); minThreads = conf.getInt(ServerConfig.RPC_MIN_THREADS, ServerConfig.RPC_MIN_THREADS_DEFAULT); - principal = Preconditions.checkNotNull(conf.get(ServerConfig.PRINCIPAL), - ServerConfig.PRINCIPAL + " is required"); - principalParts = SaslRpcServer.splitKerberosName(principal); - Preconditions.checkArgument(principalParts.length == 3, - "Kerberos principal should have 3 parts: " + principal); - keytab = Preconditions.checkNotNull(conf.get(ServerConfig.KEY_TAB), - 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."); + if (kerberos) { + principal = Preconditions.checkNotNull(conf.get(ServerConfig.PRINCIPAL), + ServerConfig.PRINCIPAL + " is required"); + principalParts = SaslRpcServer.splitKerberosName(principal); + Preconditions.checkArgument(principalParts.length == 3, + "Kerberos principal should have 3 parts: " + principal); + keytab = Preconditions.checkNotNull(conf.get(ServerConfig.KEY_TAB), + 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."); + } else { + principal = null; + principalParts = null; + keytab = null; + } serviceExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { private int count = 0; @@ -120,60 +130,24 @@ public class SentryService implements Runnable { public void run() { LoginContext loginContext = null; try { - Subject subject = new Subject(false, - Sets.newHashSet(new KerberosPrincipal(principal)), - new HashSet<Object>(), new HashSet<Object>()); - loginContext = new LoginContext("", subject, null, - KerberosConfiguration.createClientConfig(principal, new File(keytab))); - loginContext.login(); - subject = loginContext.getSubject(); - Subject.doAs(subject, new PrivilegedExceptionAction<Void>() { - @Override - public Void run() throws Exception { - Iterable<String> processorFactories = ConfUtilties.CLASS_SPLITTER - .split(conf.get(ServerConfig.PROCESSOR_FACTORIES, - ServerConfig.PROCESSOR_FACTORIES_DEFAULT).trim()); - TMultiplexedProcessor processor = new TMultiplexedProcessor(); - boolean registeredProcessor = false; - for (String processorFactory : processorFactories) { - Class<?> clazz = conf.getClassByName(processorFactory); - if (!ProcessorFactory.class.isAssignableFrom(clazz)) { - throw new IllegalArgumentException("Processor Factory " - + processorFactory + " is not a " - + ProcessorFactory.class.getName()); - } - try { - Constructor<?> constructor = clazz - .getConstructor(Configuration.class); - ProcessorFactory factory = (ProcessorFactory) constructor - .newInstance(conf); - registeredProcessor = registeredProcessor - || factory.register(processor); - } catch (Exception e) { - throw new IllegalStateException("Could not create " - + processorFactory, e); - } + if (kerberos) { + Subject subject = new Subject(false, + Sets.newHashSet(new KerberosPrincipal(principal)), + new HashSet<Object>(), new HashSet<Object>()); + loginContext = new LoginContext("", subject, null, + KerberosConfiguration.createClientConfig(principal, new File(keytab))); + loginContext.login(); + subject = loginContext.getSubject(); + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + runServer(); + return null; } - if (!registeredProcessor) { - throw new IllegalStateException( - "Failed to register any processors from " + processorFactories); - } - TServerTransport serverTransport = new TServerSocket(address); - TSaslServerTransport.Factory saslTransportFactory = new TSaslServerTransport.Factory(); - saslTransportFactory.addServerDefinition(AuthMethod.KERBEROS - .getMechanismName(), principalParts[0], principalParts[1], - ServerConfig.SASL_PROPERTIES, new GSSCallback(conf)); - TThreadPoolServer.Args args = new TThreadPoolServer.Args( - serverTransport).processor(processor) - .transportFactory(saslTransportFactory) - .protocolFactory(new TBinaryProtocol.Factory()) - .minWorkerThreads(minThreads).maxWorkerThreads(maxThreads); - thriftServer = new TThreadPoolServer(args); - LOGGER.info("Serving on " + address); - thriftServer.serve(); - return null; - } - }); + }); + } else { + runServer(); + } } catch (Throwable t) { LOGGER.error("Error starting server", t); } finally { @@ -188,6 +162,56 @@ public class SentryService implements Runnable { } } + private void runServer() throws Exception { + Iterable<String> processorFactories = ConfUtilties.CLASS_SPLITTER + .split(conf.get(ServerConfig.PROCESSOR_FACTORIES, + ServerConfig.PROCESSOR_FACTORIES_DEFAULT).trim()); + TMultiplexedProcessor processor = new TMultiplexedProcessor(); + boolean registeredProcessor = false; + for (String processorFactory : processorFactories) { + Class<?> clazz = conf.getClassByName(processorFactory); + if (!ProcessorFactory.class.isAssignableFrom(clazz)) { + throw new IllegalArgumentException("Processor Factory " + + processorFactory + " is not a " + + ProcessorFactory.class.getName()); + } + try { + Constructor<?> constructor = clazz + .getConstructor(Configuration.class); + ProcessorFactory factory = (ProcessorFactory) constructor + .newInstance(conf); + registeredProcessor = registeredProcessor + || factory.register(processor); + } catch (Exception e) { + throw new IllegalStateException("Could not create " + + processorFactory, e); + } + } + if (!registeredProcessor) { + throw new IllegalStateException( + "Failed to register any processors from " + processorFactories); + } + TServerTransport serverTransport = new TServerSocket(address); + TTransportFactory transportFactory = null; + if (kerberos) { + TSaslServerTransport.Factory saslTransportFactory = new TSaslServerTransport.Factory(); + saslTransportFactory.addServerDefinition(AuthMethod.KERBEROS + .getMechanismName(), principalParts[0], principalParts[1], + ServerConfig.SASL_PROPERTIES, new GSSCallback(conf)); + transportFactory = saslTransportFactory; + } else { + transportFactory = new TTransportFactory(); + } + TThreadPoolServer.Args args = new TThreadPoolServer.Args( + serverTransport).processor(processor) + .transportFactory(transportFactory) + .protocolFactory(new TBinaryProtocol.Factory()) + .minWorkerThreads(minThreads).maxWorkerThreads(maxThreads); + thriftServer = new TThreadPoolServer(args); + LOGGER.info("Serving on " + address); + thriftServer.serve(); + } + public InetSocketAddress getAddress() { return address; } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java index 59cb456..1b36690 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java @@ -45,6 +45,13 @@ public class ServiceConstants { } public static class ServerConfig { public static final ImmutableMap<String, String> SASL_PROPERTIES = ServiceConstants.SASL_PROPERTIES; + /** + * This configuration parameter is only meant to be used for testing purposes. + */ + public static final String SECURITY_MODE = "sentry.service.security.mode"; + public static final String SECURITY_MODE_KERBEROS = "kerberos"; + public static final String SECURITY_MODE_NONE = "none"; + public static final String ADMIN_GROUPS = "sentry.service.admin.group"; public static final String PRINCIPAL = "sentry.service.server.principal"; public static final String KEY_TAB = "sentry.service.server.keytab"; public static final String RPC_PORT = "sentry.service.server.rpc-port"; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java index e1549ca..c167837 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java @@ -23,6 +23,7 @@ import java.io.StringWriter; import javax.annotation.Nullable; import org.apache.sentry.SentryUserException; +import org.apache.sentry.provider.db.SentryAccessDeniedException; import org.apache.sentry.provider.db.SentryAlreadyExistsException; import org.apache.sentry.provider.db.SentryInvalidInputException; import org.apache.sentry.provider.db.SentryNoSuchObjectException; @@ -37,6 +38,7 @@ public enum Status { NO_SUCH_OBJECT(ThriftConstants.TSENTRY_STATUS_NO_SUCH_OBJECT), RUNTIME_ERROR(ThriftConstants.TSENTRY_STATUS_RUNTIME_ERROR), INVALID_INPUT(ThriftConstants.TSENTRY_STATUS_INVALID_INPUT), + ACCESS_DENIED(ThriftConstants.TSENTRY_STATUS_ACCESS_DENIED), UNKNOWN(-1) ; private int code; @@ -57,6 +59,9 @@ public enum Status { public static TSentryResponseStatus OK() { return Create(Status.OK, ""); } + public static TSentryResponseStatus AccessDenied(String message, Throwable t) { + return Create(Status.ACCESS_DENIED, message, t); + } public static TSentryResponseStatus AlreadyExists(String message, Throwable t) { return Create(Status.ALREADY_EXISTS, message, t); } @@ -99,6 +104,8 @@ public enum Status { throw new RuntimeException(serverErrorToString(thriftStatus)); case INVALID_INPUT: throw new SentryInvalidInputException(serverErrorToString(thriftStatus)); + case ACCESS_DENIED: + throw new SentryAccessDeniedException(serverErrorToString(thriftStatus)); case UNKNOWN: throw new AssertionError(serverErrorToString(thriftStatus)); default: http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift index 7a545be..9456274 100644 --- a/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift +++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift @@ -31,6 +31,7 @@ const i32 TSENTRY_STATUS_ALREADY_EXISTS = 1; const i32 TSENTRY_STATUS_NO_SUCH_OBJECT = 2; const i32 TSENTRY_STATUS_RUNTIME_ERROR = 3; const i32 TSENTRY_STATUS_INVALID_INPUT = 4; +const i32 TSENTRY_STATUS_ACCESS_DENIED = 5; struct TSentryResponseStatus { 1: required i32 value, http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerWithoutKerberos.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerWithoutKerberos.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerWithoutKerberos.java new file mode 100644 index 0000000..81a9ea4 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerWithoutKerberos.java @@ -0,0 +1,45 @@ +/** + * 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 createRequired 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.Set; + +import org.apache.sentry.service.thrift.SentryServiceIntegrationBase; +import org.junit.Test; + +import com.google.common.collect.Sets; + + +public class TestSentryServerWithoutKerberos extends SentryServiceIntegrationBase { + + @Override + public void beforeSetup() throws Exception { + this.kerberos = false; + } + + @Test + public void testCreateRole() throws Exception { + String requestorUserName = ADMIN_USER; + Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP); + String roleName = "admin_r"; + client.dropRoleIfExists(requestorUserName, requestorUserGroupNames, roleName); + client.createRole(requestorUserName, requestorUserGroupNames, roleName); + client.dropRole(requestorUserName, requestorUserGroupNames, roleName); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/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 index a4643bf..b97db4b 100644 --- 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 @@ -25,11 +25,17 @@ import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class TestSentryServiceFailureCase extends SentryServiceIntegrationBase { +import com.google.common.base.Strings; +public class TestSentryServiceFailureCase extends SentryServiceIntegrationBase { + private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryServiceFailureCase.class); + private static final String PEER_CALLBACK_FAILURE = "Peer indicated failure: Problem with callback handler"; @Before @Override public void setup() throws Exception { + this.kerberos = true; beforeSetup(); setupConf(); conf.set(ServerConfig.ALLOW_CONNECT, ""); @@ -37,9 +43,21 @@ public class TestSentryServiceFailureCase extends SentryServiceIntegrationBase { afterSetup(); } - @Test(expected = PrivilegedActionException.class) + @Test public void testClientServerConnectionFailure() throws Exception { - connectToSentryService(); - Assert.fail("Failed to receive Exception"); + try { + connectToSentryService(); + Assert.fail("Failed to receive Exception"); + } catch(PrivilegedActionException e) { + LOGGER.info("Excepted exception", e); + Exception cause = e.getException(); + if (cause == null) { + throw e; + } + String msg = "Exception message: " + cause.getMessage() + " to contain " + + PEER_CALLBACK_FAILURE; + Assert.assertTrue(msg, Strings.nullToEmpty(cause.getMessage()) + .contains(PEER_CALLBACK_FAILURE)); + } } } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/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 aa1e860..dcaa246 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 @@ -36,8 +36,8 @@ public class TestSentryServiceIntegration extends SentryServiceIntegrationBase { @Test public void testCreateRole() throws Exception { - String requestorUserName = "user_1"; - Set<String> requestorUserGroupNames = new HashSet<String>(); + String requestorUserName = ADMIN_USER; + Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP); String roleName = "admin_r"; client.dropRoleIfExists(requestorUserName, requestorUserGroupNames, roleName); @@ -58,8 +58,8 @@ public class TestSentryServiceIntegration extends SentryServiceIntegrationBase { @Test public void testGrantRevokePrivilege() throws Exception { String server = "server1"; - String requestorUserName = "server_admin"; - Set<String> requestorUserGroupNames = new HashSet<String>(); + String requestorUserName = ADMIN_USER; + Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP); String roleName = "admin_testdb"; String db = "testDB"; String group = "group1"; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java index ee5ca69..61bad23 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java @@ -58,6 +58,8 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc protected static final String SERVER_KERBEROS_NAME = "sentry/" + SERVER_HOST + "@" + REALM; protected static final String CLIENT_PRINCIPAL = "hive/" + SERVER_HOST; protected static final String CLIENT_KERBEROS_NAME = "hive/" + SERVER_HOST + "@" + REALM; + protected static final String ADMIN_USER = "admin_user"; + protected static final String ADMIN_GROUP = "admin_group"; protected SentryService server; protected SentryPolicyServiceClient client; @@ -68,10 +70,12 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc protected File clientKeytab; protected Subject clientSubject; protected LoginContext clientLoginContext; + protected boolean kerberos; protected final Configuration conf = new Configuration(false); @Before public void setup() throws Exception { + this.kerberos = true; beforeSetup(); setupConf(); startSentryService(); @@ -91,18 +95,23 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc } 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); - - conf.set(ServerConfig.PRINCIPAL, SERVER_KERBEROS_NAME); - conf.set(ServerConfig.KEY_TAB, serverKeytab.getPath()); + if (kerberos) { + 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); + conf.set(ServerConfig.PRINCIPAL, SERVER_KERBEROS_NAME); + conf.set(ServerConfig.KEY_TAB, serverKeytab.getPath()); + conf.set(ServerConfig.ALLOW_CONNECT, CLIENT_KERBEROS_NAME); + } else { + LOGGER.info("Stopped KDC"); + conf.set(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_NONE); + } + conf.set(ServerConfig.ADMIN_GROUPS, ADMIN_GROUP); conf.set(ServerConfig.RPC_ADDRESS, SERVER_HOST); conf.set(ServerConfig.RPC_PORT, String.valueOf(0)); - conf.set(ServerConfig.ALLOW_CONNECT, CLIENT_KERBEROS_NAME); dbDir = new File(Files.createTempDir(), "sentry_policy_db"); conf.set(ServerConfig.SENTRY_STORE_JDBC_URL, "jdbc:derby:;databaseName=" + dbDir.getPath() + ";create=true"); @@ -114,19 +123,24 @@ public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestc 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>()); - clientLoginContext = new LoginContext("", clientSubject, null, - KerberosConfiguration.createClientConfig(CLIENT_KERBEROS_NAME, clientKeytab)); - clientLoginContext.login(); - clientSubject = clientLoginContext.getSubject(); - client = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SentryPolicyServiceClient>() { - @Override - public SentryPolicyServiceClient run() throws Exception { - return new SentryServiceClientFactory().create(conf); - } - }); + final SentryServiceClientFactory factory = new SentryServiceClientFactory(); + if (kerberos) { + clientSubject = new Subject(false, Sets.newHashSet( + new KerberosPrincipal(CLIENT_KERBEROS_NAME)), new HashSet<Object>(), + new HashSet<Object>()); + clientLoginContext = new LoginContext("", clientSubject, null, + KerberosConfiguration.createClientConfig(CLIENT_KERBEROS_NAME, clientKeytab)); + clientLoginContext.login(); + clientSubject = clientLoginContext.getSubject(); + client = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SentryPolicyServiceClient>() { + @Override + public SentryPolicyServiceClient run() throws Exception { + return factory.create(conf); + } + }); + } else { + client = factory.create(conf); + } } @After http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java index 9fcebbb..e7f69ac 100644 --- a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java +++ b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java @@ -107,10 +107,6 @@ public class SimpleFileProviderBackend implements ProviderBackend { private boolean allowPerDatabaseSection; private volatile boolean initialized; - public SimpleFileProviderBackend(String resourcePath) throws IOException { - this(new Configuration(), new Path(resourcePath)); - } - public SimpleFileProviderBackend(Configuration conf, String resourcePath) throws IOException { this(conf, new Path(resourcePath)); } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestSimpleFileProvderBackend.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestSimpleFileProvderBackend.java b/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestSimpleFileProvderBackend.java index df5acdc..cd203cd 100644 --- a/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestSimpleFileProvderBackend.java +++ b/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestSimpleFileProvderBackend.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.HashSet; import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; import org.apache.sentry.core.common.ActiveRoleSet; import org.apache.sentry.provider.common.ProviderBackendContext; import org.junit.After; @@ -46,7 +47,8 @@ public class TestSimpleFileProvderBackend { public void setup() throws IOException { baseDir = Files.createTempDir(); PolicyFiles.copyToDir(baseDir, resourcePath); - backend = new SimpleFileProviderBackend(new File(baseDir, resourcePath).toString()); + backend = new SimpleFileProviderBackend(new Configuration(), new File(baseDir, resourcePath) + .toString()); context = new ProviderBackendContext(); } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-tests/sentry-tests-hive/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/pom.xml b/sentry-tests/sentry-tests-hive/pom.xml index 2b00d16..7a2c6be 100644 --- a/sentry-tests/sentry-tests-hive/pom.xml +++ b/sentry-tests/sentry-tests-hive/pom.xml @@ -195,6 +195,11 @@ limitations under the License. </dependency> <dependency> <groupId>org.apache.sentry</groupId> + <artifactId>sentry-provider-db</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.sentry</groupId> <artifactId>sentry-provider-file</artifactId> <scope>test</scope> </dependency> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java index 4f7dd2d..99ca16e 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java @@ -34,11 +34,13 @@ import java.util.Set; import junit.framework.Assert; import org.apache.hadoop.fs.FileSystem; +import org.apache.sentry.provider.db.SentryAccessDeniedException; import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Charsets; +import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.common.io.Files; @@ -48,7 +50,7 @@ public class Context { .getLogger(Context.class); public static final String AUTHZ_EXCEPTION_SQL_STATE = "42000"; - public static final String AUTHZ_EXEC_HOOK_EXCEPTION_SQL_STATE = "08S01"; + public static final String AUTHZ_LINK_FAILURE_SQL_STATE = "08S01"; public static final String AUTHZ_EXCEPTION_ERROR_MSG = "No valid privileges"; private final HiveServer hiveServer; @@ -169,6 +171,18 @@ public class Context { } } + public void assertSentryServiceAccessDenied(Statement statement, String query) + throws SQLException { + try { + statement.execute(query); + Assert.fail("Expected SQLException for '" + query + "'"); + } catch (SQLException e) { + verifyAuthzExceptionForState(e, AUTHZ_LINK_FAILURE_SQL_STATE); + Assert.assertTrue("Expected SentryAccessDeniedException in " + e.getMessage(), + Strings.nullToEmpty(e.getMessage()).contains(SentryAccessDeniedException.class + .getSimpleName())); + } + } // verify that the sqlexception is due to authorization failure public void verifyAuthzException(SQLException sqlException) throws SQLException{ @@ -177,7 +191,7 @@ public class Context { // verify that the sqlexception is due to authorization failure due to exec hooks public void verifyAuthzExecHookException(SQLException sqlException) throws SQLException{ - verifyAuthzExceptionForState(sqlException, AUTHZ_EXEC_HOOK_EXCEPTION_SQL_STATE); + verifyAuthzExceptionForState(sqlException, AUTHZ_LINK_FAILURE_SQL_STATE); } // verify that the sqlexception is due to authorization failure http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestDatabaseProvider.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestDatabaseProvider.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestDatabaseProvider.java new file mode 100644 index 0000000..b8163b3 --- /dev/null +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestDatabaseProvider.java @@ -0,0 +1,124 @@ +/* + * 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.tests.e2e.hive; + +import java.io.File; +import java.sql.Connection; +import java.sql.Statement; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.sentry.binding.hive.SentryHiveAuthorizationTaskFactoryImpl; +import org.apache.sentry.provider.db.SimpleDBProviderBackend; +import org.apache.sentry.provider.file.PolicyFile; +import org.apache.sentry.service.thrift.SentryService; +import org.apache.sentry.service.thrift.SentryServiceFactory; +import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; +import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.collect.Maps; +import com.google.common.io.Files; + +public class TestDatabaseProvider extends AbstractTestWithHiveServer { + protected static final String SERVER_HOST = "localhost"; + + private Context context; + private Map<String, String> properties; + private File dbDir; + private SentryService server; + private Configuration conf; + private PolicyFile policyFile; + + @Before + public void setup() throws Exception { + properties = Maps.newHashMap(); + conf = new Configuration(false); + policyFile = new PolicyFile(); + properties.put(HiveServerFactory.AUTHZ_PROVIDER_BACKEND, SimpleDBProviderBackend.class.getName()); + properties.put(ConfVars.HIVE_AUTHORIZATION_TASK_FACTORY.varname, + SentryHiveAuthorizationTaskFactoryImpl.class.getName()); + properties.put(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_NONE); + properties.put(ServerConfig.ADMIN_GROUPS, ADMINGROUP); + properties.put(ServerConfig.RPC_ADDRESS, SERVER_HOST); + properties.put(ServerConfig.RPC_PORT, String.valueOf(0)); + dbDir = new File(Files.createTempDir(), "sentry_policy_db"); + properties.put(ServerConfig.SENTRY_STORE_JDBC_URL, + "jdbc:derby:;databaseName=" + dbDir.getPath() + ";create=true"); + for (Map.Entry<String, String> entry : properties.entrySet()) { + conf.set(entry.getKey(), entry.getValue()); + } + server = new SentryServiceFactory().create(conf); + properties.put(ClientConfig.SERVER_RPC_ADDRESS, server.getAddress().getHostString()); + properties.put(ClientConfig.SERVER_RPC_PORT, String.valueOf(server.getAddress().getPort())); + startSentryService(); + context = createContext(properties); + } + + @After + public void tearDown() throws Exception { + if(context != null) { + context.close(); + } + if (dbDir != null) { + FileUtils.deleteQuietly(dbDir); + } + } + + private 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"); + } + } + } + + @Test + public void testBasic() throws Exception { + policyFile + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE ROLE admin_role"); + statement.execute("GRANT ALL ON DATABASE default TO ROLE admin_role"); + statement.execute("GRANT ROLE admin_role TO GROUP " + ADMINGROUP); + statement.execute("CREATE TABLE t1 (c1 string)"); + statement.execute("CREATE ROLE user_role"); + statement.execute("GRANT SELECT ON TABLE t1 TO ROLE user_role"); + statement.execute("GRANT ROLE user_role TO GROUP " + USERGROUP1); + statement.close(); + connection.close(); + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + context.assertSentryServiceAccessDenied(statement, "CREATE ROLE r2"); + statement.execute("SELECT * FROM t1"); + statement.close(); + connection.close(); + + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java index 8c145ca..416411c 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java @@ -44,7 +44,6 @@ import com.google.common.io.Resources; public class TestPrivilegesAtDatabaseScope extends AbstractTestWithStaticConfiguration { private Context context; - private File dataFile; private PolicyFile policyFile; Map <String, String >testProperties; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/63c134f3/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServerFactory.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServerFactory.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServerFactory.java index 8af3f45..f00efdb 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServerFactory.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServerFactory.java @@ -49,6 +49,7 @@ public class HiveServerFactory { public static final String WAREHOUSE_DIR = HiveConf.ConfVars.METASTOREWAREHOUSE.varname; public static final String AUTHZ_PROVIDER = HiveAuthzConf.AuthzConfVars.AUTHZ_PROVIDER.getVar(); public static final String AUTHZ_PROVIDER_RESOURCE = HiveAuthzConf.AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar(); + public static final String AUTHZ_PROVIDER_BACKEND = HiveAuthzConf.AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar(); public static final String AUTHZ_PROVIDER_FILENAME = "sentry-provider.ini"; public static final String AUTHZ_SERVER_NAME = HiveAuthzConf.AuthzConfVars.AUTHZ_SERVER_NAME.getVar(); public static final String ACCESS_TESTING_MODE = HiveAuthzConf.AuthzConfVars.SENTRY_TESTING_MODE.getVar();