sentry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shreepa...@apache.org
Subject [01/13] SENTRY-105: Remove db specific name from sentry service package (Brock via Shreepadma)
Date Mon, 10 Feb 2014 21:10:32 GMT
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);
+    }
+  }
+}


Mime
View raw message