Updated Branches:
refs/heads/db_policy_store dfc9a85a8 -> 1e121ccca
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
new file mode 100644
index 0000000..c4a0fd4
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/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.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/1e121ccc/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/KerberosConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/KerberosConfiguration.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/KerberosConfiguration.java
new file mode 100644
index 0000000..8323959
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/KerberosConfiguration.java
@@ -0,0 +1,77 @@
+/**
+ * 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.service.thrift;
+
+import java.io.File;
+import java.util.Map;
+import java.util.HashMap;
+import javax.security.auth.login.AppConfigurationEntry;
+
+public class KerberosConfiguration extends javax.security.auth.login.Configuration {
+ private String principal;
+ private String keytab;
+ private boolean isInitiator;
+
+ private KerberosConfiguration(String principal, File keytab,
+ boolean client) {
+ this.principal = principal;
+ this.keytab = keytab.getAbsolutePath();
+ this.isInitiator = client;
+ }
+
+ public static javax.security.auth.login.Configuration createClientConfig(String principal,
+ File keytab) {
+ return new KerberosConfiguration(principal, keytab, true);
+ }
+
+ public static javax.security.auth.login.Configuration createServerConfig(String principal,
+ File keytab) {
+ return new KerberosConfiguration(principal, keytab, false);
+ }
+
+ private static String getKrb5LoginModuleName() {
+ return System.getProperty("java.vendor").contains("IBM")
+ ? "com.ibm.security.auth.module.Krb5LoginModule"
+ : "com.sun.security.auth.module.Krb5LoginModule";
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, String> options = new HashMap<String, String>();
+ options.put("keyTab", keytab);
+ options.put("principal", principal);
+ options.put("useKeyTab", "true");
+ options.put("storeKey", "true");
+ options.put("doNotPrompt", "true");
+ options.put("useTicketCache", "true");
+ options.put("renewTGT", "true");
+ options.put("refreshKrb5Config", "true");
+ options.put("isInitiator", Boolean.toString(isInitiator));
+ String ticketCache = System.getenv("KRB5CCNAME");
+ if (ticketCache != null) {
+ options.put("ticketCache", ticketCache);
+ }
+ options.put("debug", "true");
+
+ return new AppConfigurationEntry[]{
+ new AppConfigurationEntry(getKrb5LoginModuleName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options)};
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ProcessorFactory.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ProcessorFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ProcessorFactory.java
new file mode 100644
index 0000000..0ba1ace
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ProcessorFactory.java
@@ -0,0 +1,30 @@
+/**
+ * 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.service.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.thrift.TMultiplexedProcessor;
+
+public abstract class ProcessorFactory {
+ protected final Configuration conf;
+ public ProcessorFactory(Configuration conf) {
+ this.conf = conf;
+ }
+
+ public abstract boolean register(TMultiplexedProcessor processor);
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
new file mode 100644
index 0000000..568e747
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
@@ -0,0 +1,251 @@
+/**
+ * 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.service.thrift;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
+import org.apache.sentry.service.thrift.Constants.ConfUtilties;
+import org.apache.sentry.service.thrift.Constants.ServerConfig;
+import org.apache.thrift.TMultiplexedProcessor;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.server.TServer;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+public class SentryService implements Runnable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentryService.class);
+
+ private static enum Status {
+ NOT_STARTED(),
+ STARTED();
+ }
+ private final Configuration conf;
+ private final InetSocketAddress address;
+ private final int maxThreads;
+ private final int minThreads;
+ private final String principal;
+ private final String[] principalParts;
+ private final String keytab;
+ private final ExecutorService serviceExecutor;
+
+ private TServer thriftServer;
+ private Status status;
+
+ public SentryService(Configuration conf) {
+ this.conf = conf;
+ int port = conf.getInt(ServerConfig.RPC_PORT, ServerConfig.RPC_PORT_DEFAULT);
+ if (port == 0) {
+ port = findFreePort();
+ }
+ this.address = NetUtils.createSocketAddr(conf.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);
+ 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.");
+ serviceExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ private int count = 0;
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, SentryService.class.getSimpleName() + "-" + (count++));
+ }
+ });
+ status = Status.NOT_STARTED;
+ }
+
+ @Override
+ 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 (!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;
+ }
+ });
+ } catch(Throwable t) {
+ LOGGER.error("Error starting server", t);
+ } finally {
+ status = Status.NOT_STARTED;
+ if (loginContext != null) {
+ try {
+ loginContext.logout();
+ } catch (LoginException e) {
+ LOGGER.error("Error logging out", e);
+ }
+ }
+ }
+ }
+
+ public InetSocketAddress getAddress() {
+ return address;
+ }
+
+ public synchronized boolean isRunning() {
+ return status == Status.STARTED && thriftServer != null && thriftServer.isServing();
+ }
+
+ public synchronized void start() {
+ if (status != Status.NOT_STARTED) {
+ throw new IllegalStateException("Cannot start when " + status);
+ }
+ LOGGER.info("Attempting to start...");
+ status = Status.STARTED;
+ serviceExecutor.submit(this);
+ }
+
+ public synchronized void stop() {
+ if (status == Status.NOT_STARTED) {
+ return;
+ }
+ LOGGER.info("Attempting to stop...");
+ if (thriftServer.isServing()) {
+ thriftServer.stop();
+ }
+ thriftServer = null;
+ status = Status.NOT_STARTED;
+ LOGGER.info("Stopped...");
+ }
+
+ private static int findFreePort() {
+ int attempts = 0;
+ while (attempts++ <= 1000) {
+ try {
+ ServerSocket s = new ServerSocket(0);
+ int port = s.getLocalPort();
+ s.close();
+ return port;
+ } catch (IOException e) {
+ // ignore and retry
+ }
+ }
+ throw new IllegalStateException("Unable to find a port after 1000 attempts");
+ }
+
+ @SuppressWarnings("deprecation")
+ public static void main(String[] args) throws Exception {
+ // XXX if more more than one argument is handled here, use an options parser
+ 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");
+ } else if(!((configFile = new File(args[1])).isFile() && configFile.canRead())) {
+ throw new IllegalArgumentException("Cannot read configuration file " + configFile);
+ }
+ Configuration conf = new Configuration(false);
+ conf.addResource(configFile.toURL());
+ final SentryService server = new SentryService(conf);
+ server.start();
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ LOGGER.info("ShutdownHook shutting down server");
+ try {
+ server.stop();
+ } catch (Throwable t) {
+ LOGGER.error("Error stopping SentryService", t);
+ }
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
new file mode 100644
index 0000000..11545a5
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
@@ -0,0 +1,30 @@
+/**
+ * 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.service.thrift;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+public class SentryServiceClientFactory {
+
+ public SentryPolicyServiceClient create(Configuration conf) throws Exception {
+ SentryPolicyServiceClient client = new SentryPolicyServiceClient(conf);
+ return client;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceFactory.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceFactory.java
new file mode 100644
index 0000000..bd7e447
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceFactory.java
@@ -0,0 +1,29 @@
+/**
+ * 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.service.thrift;
+import org.apache.hadoop.conf.Configuration;
+
+public class SentryServiceFactory {
+
+ public SentryService create(Configuration conf) throws Exception {
+ SentryService server = new SentryService(conf);
+ return server;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
new file mode 100644
index 0000000..73ef64c
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java
@@ -0,0 +1,77 @@
+/**
+ * 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.service.thrift;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.annotation.Nullable;
+
+import org.apache.sentry.service.thrift.Constants.ThriftConstants;
+
+/**
+ * Simple factory to make returning TSentryStatus objects easy
+ */
+public enum Status {
+ OK(ThriftConstants.TSENTRY_STATUS_OK),
+ ALREADY_EXISTS(ThriftConstants.TSENTRY_STATUS_ALREADY_EXISTS),
+ NO_SUCH_OBJECT(ThriftConstants.TSENTRY_STATUS_NO_SUCH_OBJECT),
+ RUNTIME_ERROR(ThriftConstants.TSENTRY_STATUS_RUNTIME_ERROR),
+ UNKNOWN(-1)
+ ;
+ private int code;
+ private Status(int code) {
+ this.code = code;
+ }
+ public int getCode() {
+ return code;
+ }
+ public static Status fromCode(int code) {
+ for (Status status : Status.values()) {
+ if (status.getCode() == code) {
+ return status;
+ }
+ }
+ return Status.UNKNOWN;
+ }
+ public static TSentryResponseStatus OK() {
+ return Create(Status.OK, "");
+ }
+ public static TSentryResponseStatus AlreadyExists(String message, Throwable t) {
+ return Create(Status.ALREADY_EXISTS, message, t);
+ }
+ public static TSentryResponseStatus NoSuchObject(String message, Throwable t) {
+ return Create(Status.NO_SUCH_OBJECT, message, t);
+ }
+ public static TSentryResponseStatus Create(Status value, String message) {
+ return Create(value, message, null);
+ }
+ public static TSentryResponseStatus Create(Status value, String message, @Nullable Throwable t) {
+ TSentryResponseStatus status = new TSentryResponseStatus();
+ status.setValue(value.getCode());
+ status.setMessage(message);
+ if (t != null) {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+ t.printStackTrace(printWriter);
+ printWriter.close();
+ status.setStack(stringWriter.toString());
+ }
+ return status;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
new file mode 100644
index 0000000..ed0ebc5
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift
@@ -0,0 +1,40 @@
+#!/usr/local/bin/thrift -java
+
+/**
+ * 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.
+ */
+
+include "share/fb303/if/fb303.thrift"
+
+namespace java org.apache.sentry.service.thrift
+namespace php sentry.service.thrift
+namespace cpp Apache.Sentry.Service.Thrift
+
+const i32 TSENTRY_SERVICE_V1 = 1;
+
+const i32 TSENTRY_STATUS_OK = 0;
+const i32 TSENTRY_STATUS_ALREADY_EXISTS = 1;
+const i32 TSENTRY_STATUS_NO_SUCH_OBJECT = 2;
+const i32 TSENTRY_STATUS_RUNTIME_ERROR = 3;
+
+struct TSentryResponseStatus {
+1: required i32 value,
+// message will be set to empty string when status is OK
+2: required string message
+3: optional string stack
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift b/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift
new file mode 100644
index 0000000..5029fff
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift
@@ -0,0 +1,123 @@
+#!/usr/local/bin/thrift -java
+
+/**
+ * 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.
+ */
+
+#
+# Thrift Service that the MetaStore is built on
+#
+
+include "share/fb303/if/fb303.thrift"
+include "sentry_common_service.thrift"
+
+namespace java org.apache.sentry.provider.db.service.thrift
+namespace php sentry.provider.db.service.thrift
+namespace cpp Apache.Sentry.Provider.Db.Service.Thrift
+
+struct TSentryPrivilege {
+1: required string privilegeScope,
+2: required string privilegeName,
+3: required string serverName,
+4: optional string dbName,
+5: optional string tableName,
+6: optional string URI,
+7: required string action,
+8: required i64 createTime,
+9: required string grantorPrincipal
+}
+
+struct TSentryRole {
+1: required string roleName,
+2: required set<TSentryPrivilege> privileges,
+3: required i64 createTime,
+4: required string grantorPrincipal
+}
+// TODO fill out
+struct TSentryGroup {
+1: required string groupName
+}
+
+struct TCreateSentryRoleRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+3: required TSentryRole role
+}
+struct TCreateSentryRoleResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TCreateSentryPrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+3: required TSentryPrivilege privilege
+}
+struct TCreateSentryPrivilegeResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TCreateSentryPrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+3: required TSentryPrivilege privilege
+}
+struct TCreateSentryPrivilegeResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TAlterSentryRoleAddGroupsRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+3: required string roleName,
+4: required set<TSentryGroup> groups
+}
+struct TAlterSentryRoleAddGroupsResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TAlterSentryRoleDeleteGroupsRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+}
+struct TAlterSentryRoleDeleteGroupsResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TListSentryRolesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string userName,
+3: optional string groupName,
+4: optional string roleName
+}
+struct TListSentryRolesResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+2: required set<TSentryRole> roles
+}
+
+service SentryPolicyService
+{
+ TCreateSentryRoleResponse create_sentry_role(1:TCreateSentryRoleRequest request)
+ //TDropSentryRoleResponse drop_sentry_role(1:TDropSentryRoleRequest request)
+
+ TCreateSentryPrivilegeResponse create_sentry_privilege(1:TCreateSentryPrivilegeRequest request)
+ //TDropSentryPrivilegeResponse drop_sentry_privilege(1:TDropSentryPrivilegeRequest request)
+
+ TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(1:TAlterSentryRoleAddGroupsRequest request)
+ TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(1:TAlterSentryRoleDeleteGroupsRequest request)
+
+ TListSentryRolesResponse list_sentry_roles(1:TListSentryRolesRequest request)
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
deleted file mode 100644
index e94eb78..0000000
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/SentryServiceIntegrationBase.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * 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.io.File;
-import java.security.PrivilegedExceptionAction;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.concurrent.TimeoutException;
-
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.LoginContext;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
-import org.apache.hadoop.minikdc.MiniKdc;
-import org.apache.sentry.provider.db.service.thrift.Constants.ClientConfig;
-import org.apache.sentry.provider.db.service.thrift.Constants.ServerConfig;
-import org.junit.After;
-import org.junit.Before;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Sets;
-
-public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestcase {
- private static final Logger LOGGER = LoggerFactory.getLogger(SentryServiceIntegrationBase.class);
-
- static {
- if (System.getProperty("sun.security.krb5.debug", "").trim().isEmpty()) {
- System.setProperty("sun.security.krb5.debug", String.valueOf("true"));
- }
- }
-
- protected static final String SERVER_HOST = "localhost";
- protected static final String REALM = "EXAMPLE.COM";
- protected static final String SERVER_PRINCIPAL = "sentry/" + SERVER_HOST;
- 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 SentryService server;
- protected SentryServiceClient client;
- protected MiniKdc kdc;
- protected File kdcWorkDir;
- protected File serverKeytab;
- 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);
-
- 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()));
- }
-
- 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<SentryServiceClient>() {
- @Override
- public SentryServiceClient run() throws Exception {
- return new SentryServiceClientFactory().create(conf);
- }
- });
- }
-
- @After
- public void tearDown() throws Exception {
- beforeTeardown();
- if(client != null) {
- client.close();
- }
- if(clientLoginContext != null) {
- try {
- clientLoginContext.logout();
- } catch (Exception e) {
- LOGGER.warn("Error logging client out", e);
- }
- }
- if(server != null) {
- server.stop();
- }
- afterTeardown();
- }
-
- public void beforeSetup() throws Exception {
-
- }
- public void afterSetup() throws Exception {
-
- }
- public void beforeTeardown() throws Exception {
-
- }
- public void afterTeardown() throws Exception {
-
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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 063a5b0..cb82bef 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
@@ -18,16 +18,15 @@
package org.apache.sentry.provider.db.service.thrift;
-import org.apache.sentry.provider.db.service.thrift.Constants.ServerConfig;
+import java.security.PrivilegedActionException;
+
+import org.apache.sentry.service.thrift.SentryServiceIntegrationBase;
+import org.apache.sentry.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 {
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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 3988229..fc01aaf 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,13 +19,8 @@
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;
-import org.apache.sentry.service.api.TSentryRole;
-import org.apache.sentry.service.api.TSentryStatus;
-import org.junit.Assert;
+import org.apache.sentry.service.thrift.Constants.ThriftConstants;
+import org.apache.sentry.service.thrift.SentryServiceIntegrationBase;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +31,7 @@ public class TestSentryServiceIntegration extends SentryServiceIntegrationBase {
@Test
public void testClientServerConnection() throws Exception {
TCreateSentryRoleRequest req = new TCreateSentryRoleRequest();
+ req.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
TSentryRole role = new TSentryRole();
role.setRoleName("admin_r");
role.setCreateTime(System.currentTimeMillis());
@@ -44,11 +40,7 @@ public class TestSentryServiceIntegration extends SentryServiceIntegrationBase {
req.setUserName("admin");
req.setRole(role);
TCreateSentryRoleResponse resp = client.createRole(req);
- if (resp.getStatus().getValue() == TSentryStatus.OK) {
- LOGGER.info("Successfully opened connection");
- } else {
- Assert.fail("Received invalid status: " + resp.getStatus().getMessage()
- + ":\nstack:" + resp.getStatus().getStack());
- }
+ assertOK(resp.getStatus());
+ LOGGER.info("Successfully opened connection");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/1e121ccc/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
new file mode 100644
index 0000000..6b5b7d6
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
@@ -0,0 +1,168 @@
+/**
+ * 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.service.thrift;
+import java.io.File;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.concurrent.TimeoutException;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.service.thrift.Constants.ClientConfig;
+import org.apache.sentry.service.thrift.Constants.ServerConfig;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+
+public abstract class SentryServiceIntegrationBase extends KerberosSecurityTestcase {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentryServiceIntegrationBase.class);
+
+ static {
+ if (System.getProperty("sun.security.krb5.debug", "").trim().isEmpty()) {
+ System.setProperty("sun.security.krb5.debug", String.valueOf("true"));
+ }
+ }
+
+ protected static final String SERVER_HOST = "localhost";
+ protected static final String REALM = "EXAMPLE.COM";
+ protected static final String SERVER_PRINCIPAL = "sentry/" + SERVER_HOST;
+ 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 SentryService server;
+ protected SentryPolicyServiceClient client;
+ protected MiniKdc kdc;
+ protected File kdcWorkDir;
+ protected File serverKeytab;
+ 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);
+
+ 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()));
+ }
+
+ 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);
+ }
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ beforeTeardown();
+ if(client != null) {
+ client.close();
+ }
+ if(clientLoginContext != null) {
+ try {
+ clientLoginContext.logout();
+ } catch (Exception e) {
+ LOGGER.warn("Error logging client out", e);
+ }
+ }
+ if(server != null) {
+ server.stop();
+ }
+ afterTeardown();
+ }
+
+ public void beforeSetup() throws Exception {
+
+ }
+ public void afterSetup() throws Exception {
+
+ }
+ public void beforeTeardown() throws Exception {
+
+ }
+ public void afterTeardown() throws Exception {
+
+ }
+ protected static void assertOK(TSentryResponseStatus resp) {
+ if (resp.getValue() != Status.OK.getCode()) {
+ String message = "Response: " + Status.fromCode(resp.getValue()) + ", Code: "
+ + resp.getValue() + ", Message: " + resp.getMessage();
+ String stackTrace = Strings.nullToEmpty(resp.getStack()).trim();
+ if (!stackTrace.isEmpty()) {
+ message += ", StackTrace: " + stackTrace;
+ }
+ Assert.fail(message);
+ }
+ }
+}
|