You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sh...@apache.org on 2014/03/13 22:21:17 UTC
[02/13] SENTRY-143: Merge db_policy_store branch into master (Brock
Noland via Shreepadma Venugopalan)
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ConnectionDeniedException.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ConnectionDeniedException.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ConnectionDeniedException.java
new file mode 100644
index 0000000..02c5eb3
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ConnectionDeniedException.java
@@ -0,0 +1,36 @@
+/**
+ * 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 javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class ConnectionDeniedException extends UnsupportedCallbackException {
+
+ private static final long serialVersionUID = 653174214903923178L;
+ private String connectionPrincipal;
+
+ public ConnectionDeniedException(Callback callback, String message, String connectionPrincipal) {
+ super(callback, message);
+ this.connectionPrincipal = connectionPrincipal;
+ }
+
+ public String getConnectionPrincipal() {
+ return connectionPrincipal;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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/644e8be3/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..3022f67
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/KerberosConfiguration.java
@@ -0,0 +1,78 @@
+/**
+ * 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.HashMap;
+import java.util.Map;
+
+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/644e8be3/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..07b3472
--- /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) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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..fbb0eef
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
@@ -0,0 +1,272 @@
+/**
+ * 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.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.Options;
+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.Command;
+import org.apache.sentry.service.thrift.ServiceConstants.ConfUtilties;
+import org.apache.sentry.service.thrift.ServiceConstants.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");
+ }
+ public static class CommandImpl implements Command {
+ @Override
+ @SuppressWarnings("deprecation")
+ public void run(String[] args) throws Exception {
+ CommandLineParser parser = new GnuParser();
+ Options options = new Options();
+ options.addOption(null, ServiceConstants.ServiceArgs.CONFIG_FILE,
+ true, "Sentry Service configuration file");
+ CommandLine commandLine = parser.parse(options, args);
+ String configFileName = commandLine.getOptionValue(ServiceConstants.
+ ServiceArgs.CONFIG_FILE);
+ File configFile = null;
+ if (configFileName == null) {
+ throw new IllegalArgumentException("Usage: " + ServiceConstants.ServiceArgs.CONFIG_FILE +
+ " path/to/sentry-service.xml");
+ } else if(!((configFile = new File(configFileName)).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/644e8be3/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/644e8be3/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/644e8be3/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
new file mode 100644
index 0000000..253f88e
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
@@ -0,0 +1,78 @@
+/**
+ * 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.HashMap;
+import java.util.Map;
+
+import javax.security.sasl.Sasl;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+
+public class ServiceConstants {
+
+ private static final ImmutableMap<String, String> SASL_PROPERTIES;
+
+ static {
+ Map<String, String> saslProps = new HashMap<String, String>();
+ saslProps.put(Sasl.SERVER_AUTH, "true");
+ saslProps.put(Sasl.QOP, "auth-conf");
+ SASL_PROPERTIES = ImmutableMap.copyOf(saslProps);
+ }
+
+ public static class ConfUtilties {
+ public static final Splitter CLASS_SPLITTER = Splitter.onPattern("[\\s,]")
+ .trimResults().omitEmptyStrings();
+ }
+ public static class ServiceArgs {
+ public static final String CONFIG_FILE = "--conf-file";
+ }
+ public static class ServerConfig {
+ public static final ImmutableMap<String, String> SASL_PROPERTIES = ServiceConstants.SASL_PROPERTIES;
+ public static final String PRINCIPAL = "sentry.service.server.principal";
+ public static final String KEY_TAB = "sentry.service.server.keytab";
+ public static final String RPC_PORT = "sentry.service.server.rpc-port";
+ public static final int RPC_PORT_DEFAULT = 8038;
+ public static final String RPC_ADDRESS = "sentry.service.server.rpc-address";
+ public static final String RPC_ADDRESS_DEFAULT = "0.0.0.0";
+ public static final String RPC_MAX_THREADS = "sentry.service.server-max-threads";
+ public static final int RPC_MAX_THREADS_DEFAULT = 500;
+ public static final String RPC_MIN_THREADS = "sentry.service.server-min-threads";
+ public static final int RPC_MIN_THREADS_DEFAULT = 10;
+ public static final String ALLOW_CONNECT = "sentry.service.allow.connect";
+ public static final String PROCESSOR_FACTORIES = "sentry.service.processor.factories";
+ public static final String PROCESSOR_FACTORIES_DEFAULT =
+ "org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessorFactory";
+ }
+ public static class ClientConfig {
+ public static final ImmutableMap<String, String> SASL_PROPERTIES = ServiceConstants.SASL_PROPERTIES;
+ public static final String SERVER_RPC_PORT = "sentry.service.client.server.rpc-port";
+ public static final int SERVER_RPC_PORT_DEFAULT = ServerConfig.RPC_PORT_DEFAULT;
+ public static final String SERVER_RPC_ADDRESS = "sentry.service.client.server.rpc-address";
+ public static final String SERVER_RPC_CONN_TIMEOUT = "sentry.service.client.server.rpc-connection-timeout";
+ public static final int SERVER_RPC_CONN_TIMEOUT_DEFAULT = 200000;
+ }
+
+ /**
+ * Thrift generates terrible constant class names
+ */
+ public static class ThriftConstants extends org.apache.sentry.service.thrift.sentry_common_serviceConstants {
+ public static final int TSENTRY_SERVICE_VERSION_CURRENT = TSENTRY_SERVICE_V1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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..1686780
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/Status.java
@@ -0,0 +1,84 @@
+/**
+ * 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.ServiceConstants.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),
+ INVALID_INPUT(ThriftConstants.TSENTRY_STATUS_INVALID_INPUT),
+ 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 RuntimeError(String message, Throwable t) {
+ return Create(Status.RUNTIME_ERROR, message, t);
+ }
+ public static TSentryResponseStatus Create(Status value, String message) {
+ return Create(value, message, null);
+ }
+ public static TSentryResponseStatus InvalidInput(String message, Throwable t) {
+ return Create(Status.INVALID_INPUT, message, t);
+ }
+ 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/644e8be3/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
new file mode 100644
index 0000000..85d5085
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
@@ -0,0 +1,113 @@
+--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.
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+CREATE TABLE `SENTRY_DB_PRIVILEGE` (
+ `DB_PRIVILEGE_ID` BIGINT NOT NULL,
+ `PRIVILEGE_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, -- Name of the privilege
+ `PRIVILEGE_SCOPE` VARCHAR(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, -- Scope. Valid values are Server, Database, Table
+ `SERVER_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
+ `DATABASE_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
+ `TABLE_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
+ `URI` VARCHAR(4000) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
+ `PRIVILEGE` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, -- Allowed action. Valid values are ALL, INSERT, SELECT
+ `CREATE_TIME` BIGINT NOT NULL,
+ `GRANTOR_PRINCIPAL` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL -- principal of the creator
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `SENTRY_ROLE` (
+ `ROLE_ID` BIGINT NOT NULL,
+ `ROLE_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
+ `CREATE_TIME` BIGINT NOT NULL,
+ `ROLE_OWNER` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `SENTRY_GROUP` (
+ `GROUP_ID` BIGINT NOT NULL,
+ `GROUP_NAME` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
+ `CREATE_TIME` BIGINT NOT NULL,
+ `GRANTOR_PRINCIPAL` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `SENTRY_ROLE_DB_PRIVILEGE_MAP` (
+ `ROLE_PRIVILEGE_MAP_ID` BIGINT NOT NULL,
+ `ROLE_ID` BIGINT NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ `DB_PRIVILEGE_ID` BIGINT NOT NULL -- FK to SENTRY_DB_PRIVILEGE.DB_PRIVILEGE_ID
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `SENTRY_ROLE_GROUP_MAP` (
+ `ROLE_GROUP_MAP_ID` BIGINT NOT NULL,
+ `ROLE_ID` BIGINT NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ `GROUP_ID` BIGINT NOT NULL -- FK to SENTRY_GROUP.GROUP_ID
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `SENTRY_VERSION` (
+ `VER_ID` BIGINT NOT NULL,
+ `SCHEMA_VERSION` VARCHAR(127) NOT NULL,
+ `VERSION_COMMENT` VARCHAR(255) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `SENTRY_DB_PRIVILEGE`
+ ADD CONSTRAINT `SENTRY_DB_PRIV_PK` PRIMARY KEY (`DB_PRIVILEGE_ID`);
+
+ALTER TABLE `SENTRY_ROLE`
+ ADD CONSTRAINT `SENTRY_ROLE_PK` PRIMARY KEY (`ROLE_ID`);
+
+ALTER TABLE `SENTRY_GROUP`
+ ADD CONSTRAINT `SENTRY_GROUP_PK` PRIMARY KEY (`GROUP_ID`);
+
+ALTER TABLE `SENTRY_ROLE_DB_PRIVILEGE_MAP`
+ ADD CONSTRAINT `SENTRY_ROLE_DB_PRIV_MAP_PK` PRIMARY KEY (`ROLE_PRIVILEGE_MAP_ID`);
+
+ALTER TABLE `SENTRY_ROLE_GROUP_MAP`
+ ADD CONSTRAINT `SENTRY_ROLE_GROUP_MAP_PK` PRIMARY KEY (`ROLE_GROUP_MAP_ID`);
+
+ALTER TABLE `SENTRY_VERSION`
+ ADD CONSTRAINT `SENTRY_VERSION` PRIMARY KEY (`VER_ID`);
+
+ALTER TABLE `SENTRY_DB_PRIVILEGE`
+ ADD CONSTRAINT `SENTRY_DB_PRIV_PRIV_NAME_UNIQ` UNIQUE (`PRIVILEGE_NAME`);
+
+ALTER TABLE `SENTRY_ROLE`
+ ADD CONSTRAINT `SENTRY_ROLE_ROLE_NAME_UNIQUE` UNIQUE (`ROLE_NAME`);
+
+ALTER TABLE `SENTRY_ROLE_DB_PRIVILEGE_MAP`
+ ADD CONSTRAINT `SEN_RLE_DB_PRV_MAP_SN_RLE_FK`
+ FOREIGN KEY (`ROLE_ID`) REFERENCES `SENTRY_ROLE`(`ROLE_ID`);
+
+ALTER TABLE `SENTRY_ROLE_DB_PRIVILEGE_MAP`
+ ADD CONSTRAINT `SEN_RL_DB_PRV_MAP_SN_DB_PRV_FK`
+ FOREIGN KEY (`DB_PRIVILEGE_ID`) REFERENCES `SENTRY_DB_PRIVILEGE`(`DB_PRIVILEGE_ID`);
+
+ALTER TABLE `SENTRY_ROLE_GROUP_MAP`
+ ADD CONSTRAINT `SEN_ROLE_GROUP_MAP_SEN_ROLE_FK`
+ FOREIGN KEY (`ROLE_ID`) REFERENCES `SENTRY_ROLE`(`ROLE_ID`);
+
+ALTER TABLE `SENTRY_ROLE_GROUP_MAP`
+ ADD CONSTRAINT `SEN_ROLE_GROUP_MAP_SEN_GRP_FK`
+ FOREIGN KEY (`GROUP_ID`) REFERENCES `SENTRY_GROUP`(`GROUP_ID`);
+
+INSERT INTO SENTRY_VERSION (VER_ID, SCHEMA_VERSION, VERSION_COMMENT) VALUES (1, '1.4.0', 'Sentry release version 1.4.0');
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
new file mode 100644
index 0000000..0508d45
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
@@ -0,0 +1,101 @@
+--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.
+
+CREATE TABLE "SENTRY_DB_PRIVILEGE" (
+ "DB_PRIVILEGE_ID" NUMBER NOT NULL,
+ "PRIVILEGE_NAME" VARCHAR2(128) NOT NULL, -- Name of the privilege
+ "PRIVILEGE_SCOPE" VARCHAR2(32) NOT NULL, -- Scope. Valid values are Server, Database, Table
+ "SERVER_NAME" VARCHAR2(128) NOT NULL,
+ "DATABASE_NAME" VARCHAR2(128) NULL,
+ "TABLE_NAME" VARCHAR2(128) NULL,
+ "URI" VARCHAR2(4000) NULL,
+ "PRIVILEGE" VARCHAR2(128) NOT NULL, -- Allowed action. Valid values are ALL, INSERT, SELECT
+ "CREATE_TIME" NUMBER NOT NULL,
+ "GRANTOR_PRINCIPAL" VARCHAR(128) NOT NULL -- principal of the creator
+);
+
+CREATE TABLE "SENTRY_ROLE" (
+ "ROLE_ID" NUMBER NOT NULL,
+ "ROLE_NAME" VARCHAR2(128) NOT NULL,
+ "CREATE_TIME" NUMBER NOT NULL,
+ "ROLE_OWNER" VARCHAR2(128) NOT NULL
+);
+
+CREATE TABLE "SENTRY_GROUP" (
+ "GROUP_ID" NUMBER NOT NULL,
+ "GROUP_NAME" VARCHAR2(128) NOT NULL,
+ "CREATE_TIME" NUMBER NOT NULL,
+ "GRANTOR_PRINCIPAL" VARCHAR2(128) NOT NULL
+);
+
+CREATE TABLE "SENTRY_ROLE_DB_PRIVILEGE_MAP" (
+ "ROLE_PRIVILEGE_MAP_ID" NUMBER NOT NULL,
+ "ROLE_ID" NUMBER NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ "DB_PRIVILEGE_ID" NUMBER NOT NULL -- FK to SENTRY_DB_PRIVILEGE.DB_PRIVILEGE_ID
+);
+
+CREATE TABLE "SENTRY_ROLE_GROUP_MAP" (
+ "ROLE_GROUP_MAP_ID" NUMBER NOT NULL,
+ "ROLE_ID" NUMBER NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ "GROUP_ID" NUMBER NOT NULL -- FK to SENTRY_GROUP.GROUP_ID
+);
+
+CREATE TABLE "SENTRY_VERSION" (
+ "VER_ID" NUMBER NOT NULL,
+ "SCHEMA_VERSION" VARCHAR(127) NOT NULL,
+ "VERSION_COMMENT" VARCHAR(255) NOT NULL
+);
+
+ALTER TABLE "SENTRY_DB_PRIVILEGE"
+ ADD CONSTRAINT "SENTRY_DB_PRIV_PK" PRIMARY KEY ("DB_PRIVILEGE_ID");
+
+ALTER TABLE "SENTRY_ROLE"
+ ADD CONSTRAINT "SENTRY_ROLE_PK" PRIMARY KEY ("ROLE_ID");
+
+ALTER TABLE "SENTRY_GROUP"
+ ADD CONSTRAINT "SENTRY_GROUP_PK" PRIMARY KEY ("GROUP_ID");
+
+ALTER TABLE "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SENTRY_ROLE_DB_PRIV_MAP_PK" PRIMARY KEY ("ROLE_PRIVILEGE_MAP_ID");
+
+ALTER TABLE "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SENTRY_ROLE_GROUP_MAP_PK" PRIMARY KEY ("ROLE_GROUP_MAP_ID");
+
+ALTER TABLE "SENTRY_VERSION" ADD CONSTRAINT "SENTRY_VERSION_PK" PRIMARY KEY ("VER_ID");
+
+ALTER TABLE "SENTRY_DB_PRIVILEGE"
+ ADD CONSTRAINT "SENTRY_DB_PRIV_PRIV_NAME_UNIQ" UNIQUE ("PRIVILEGE_NAME");
+
+ALTER TABLE "SENTRY_ROLE"
+ ADD CONSTRAINT "SENTRY_ROLE_ROLE_NAME_UNIQUE" UNIQUE ("ROLE_NAME");
+
+ALTER TABLE "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SEN_RLE_DB_PRV_MAP_SN_RLE_FK"
+ FOREIGN KEY ("ROLE_ID") REFERENCES "SENTRY_ROLE"("ROLE_ID") INITIALLY DEFERRED;
+
+ALTER TABLE "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SEN_RL_DB_PRV_MAP_SN_DB_PRV_FK"
+ FOREIGN KEY ("DB_PRIVILEGE_ID") REFERENCES "SENTRY_DB_PRIVILEGE"("DB_PRIVILEGE_ID") INITIALLY DEFERRED;
+
+ALTER TABLE "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SEN_ROLE_GROUP_MAP_SEN_ROLE_FK"
+ FOREIGN KEY ("ROLE_ID") REFERENCES "SENTRY_ROLE"("ROLE_ID") INITIALLY DEFERRED;
+
+ALTER TABLE "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SEN_ROLE_GROUP_MAP_SEN_GRP_FK"
+ FOREIGN KEY ("GROUP_ID") REFERENCES "SENTRY_GROUP"("GROUP_ID") INITIALLY DEFERRED;
+
+INSERT INTO VERSION (VER_ID, SCHEMA_VERSION, VERSION_COMMENT) VALUES (1, '1.4.0', 'Sentry release version 1.4.0');
+
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
new file mode 100644
index 0000000..7298923
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
@@ -0,0 +1,115 @@
+--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.
+
+START TRANSACTION;
+
+SET statement_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = off;
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+SET escape_string_warning = off;
+SET search_path = public, pg_catalog;
+SET default_tablespace = '';
+SET default_with_oids = false;
+
+CREATE TABLE "SENTRY_DB_PRIVILEGE" (
+ "DB_PRIVILEGE_ID" BIGINT NOT NULL,
+ "PRIVILEGE_NAME" character varying(128) NOT NULL, -- Name of the privilege
+ "PRIVILEGE_SCOPE" character varying(32) NOT NULL, -- Scope. Valid values are Server, Database, Table
+ "SERVER_NAME" character varying(128) NOT NULL,
+ "DATABASE_NAME" character varying(128) DEFAULT NULL::character varying,
+ "TABLE_NAME" character varying(128) DEFAULT NULL::character varying,
+ "URI" character varying(4000) DEFAULT NULL::character varying,
+ "PRIVILEGE" character varying(128) NOT NULL, -- Allowed action. Valid values are ALL, INSERT, SELECT
+ "CREATE_TIME" BIGINT NOT NULL,
+ "GRANTOR_PRINCIPAL" VARCHAR(128) NOT NULL -- principal of the creator
+);
+
+CREATE TABLE "SENTRY_ROLE" (
+ "ROLE_ID" BIGINT NOT NULL,
+ "ROLE_NAME" character varying(128) NOT NULL,
+ "CREATE_TIME" BIGINT NOT NULL,
+ "ROLE_OWNER" character varying(128) NOT NULL
+);
+
+CREATE TABLE "SENTRY_GROUP" (
+ "GROUP_ID" BIGINT NOT NULL,
+ "GROUP_NAME" character varying(128) NOT NULL,
+ "CREATE_TIME" BIGINT NOT NULL,
+ "GRANTOR_PRINCIPAL" character varying(128) NOT NULL
+);
+
+CREATE TABLE "SENTRY_ROLE_DB_PRIVILEGE_MAP" (
+ "ROLE_PRIVILEGE_MAP_ID" BIGINT NOT NULL,
+ "ROLE_ID" BIGINT NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ "DB_PRIVILEGE_ID" BIGINT NOT NULL -- FK to SENTRY_DB_PRIVILEGE.DB_PRIVILEGE_ID
+);
+
+CREATE TABLE "SENTRY_ROLE_GROUP_MAP" (
+ "ROLE_GROUP_MAP_ID" BIGINT NOT NULL,
+ "ROLE_ID" BIGINT NOT NULL, -- FK to SENTRY_ROLE.ROLE_ID
+ "GROUP_ID" BIGINT NOT NULL -- FK to SENTRY_GROUP.GROUP_ID
+);
+
+CREATE TABLE "SENTRY_VERSION" (
+ "VER_ID" bigint,
+ "SCHEMA_VERSION" character varying(127) NOT NULL,
+ "VERSION_COMMENT" character varying(255) NOT NULL
+);
+
+
+ALTER TABLE ONLY "SENTRY_DB_PRIVILEGE"
+ ADD CONSTRAINT "SENTRY_DB_PRIV_PK" PRIMARY KEY ("DB_PRIVILEGE_ID");
+
+ALTER TABLE ONLY "SENTRY_ROLE"
+ ADD CONSTRAINT "SENTRY_ROLE_PK" PRIMARY KEY ("ROLE_ID");
+
+ALTER TABLE ONLY "SENTRY_GROUP"
+ ADD CONSTRAINT "SENTRY_GROUP_PK" PRIMARY KEY ("GROUP_ID");
+
+ALTER TABLE ONLY "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SENTRY_ROLE_DB_PRIV_MAP_PK" PRIMARY KEY ("ROLE_PRIVILEGE_MAP_ID");
+
+ALTER TABLE ONLY "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SENTRY_ROLE_GROUP_MAP_PK" PRIMARY KEY ("ROLE_GROUP_MAP_ID");
+
+ALTER TABLE ONLY "SENTRY_VERSION" ADD CONSTRAINT "SENTRY_VERSION_PK" PRIMARY KEY ("VER_ID");
+
+ALTER TABLE ONLY "SENTRY_DB_PRIVILEGE"
+ ADD CONSTRAINT "SENTRY_DB_PRIV_PRIV_NAME_UNIQ" UNIQUE ("PRIVILEGE_NAME");
+
+ALTER TABLE ONLY "SENTRY_ROLE"
+ ADD CONSTRAINT "SENTRY_ROLE_ROLE_NAME_UNIQUE" UNIQUE ("ROLE_NAME");
+
+ALTER TABLE ONLY "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SEN_RLE_DB_PRV_MAP_SN_RLE_FK"
+ FOREIGN KEY ("ROLE_ID") REFERENCES "SENTRY_ROLE"("ROLE_ID") DEFERRABLE;
+
+ALTER TABLE ONLY "SENTRY_ROLE_DB_PRIVILEGE_MAP"
+ ADD CONSTRAINT "SEN_RL_DB_PRV_MAP_SN_DB_PRV_FK"
+ FOREIGN KEY ("DB_PRIVILEGE_ID") REFERENCES "SENTRY_DB_PRIVILEGE"("DB_PRIVILEGE_ID") DEFERRABLE;
+
+ALTER TABLE ONLY "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SEN_ROLE_GROUP_MAP_SEN_ROLE_FK"
+ FOREIGN KEY ("ROLE_ID") REFERENCES "SENTRY_ROLE"("ROLE_ID") DEFERRABLE;
+
+ALTER TABLE ONLY "SENTRY_ROLE_GROUP_MAP"
+ ADD CONSTRAINT "SEN_ROLE_GROUP_MAP_SEN_GRP_FK"
+ FOREIGN KEY ("GROUP_ID") REFERENCES "SENTRY_GROUP"("GROUP_ID") DEFERRABLE;
+
+INSERT INTO "SENTRY_VERSION" ("VER_ID", "SCHEMA_VERSION", "VERSION_COMMENT") VALUES (1, '1.4.0', 'Sentry release version 1.4.0');
+
+COMMIT;
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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..7a545be
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift
@@ -0,0 +1,41 @@
+#!/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;
+const i32 TSENTRY_STATUS_INVALID_INPUT = 4;
+
+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/644e8be3/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..b3f7d6e
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift
@@ -0,0 +1,150 @@
+#!/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, # Valid values are SERVER, DATABASE, TABLE
+2: optional string privilegeName, # Generated on server side
+3: required string serverName,
+4: optional string dbName,
+5: optional string tableName,
+6: optional string URI,
+7: required string action,
+8: optional i64 createTime, # Set on server side
+9: optional string grantorPrincipal # Set on server side
+}
+
+struct TSentryRole {
+1: required string roleName,
+# TODO privs should not be part of Sentry role as
+# they are created when a grant is executed
+# They need to be returned as part of the list role API, else
+# there would be another round trip
+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 requestorUserName,
+3: required TSentryRole role,
+4: required set<string> requestorGroupName
+}
+struct TCreateSentryRoleResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TListSentryRolesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string requestorUserName, # user on whose behalf the request is issued
+3: optional string rolerequestorGroupName, # list roles for this group
+4: required string roleName,
+5: required set<string> requestorGroupName # groups the requesting user belongs to
+}
+struct TListSentryRolesResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+2: required set<TSentryRole> roles
+}
+
+struct TDropSentryRoleRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string requestorUserName,
+3: required string roleName,
+4: required set<string> requestorGroupName
+}
+struct TDropSentryRoleResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TAlterSentryRoleAddGroupsRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string requestorUserName,
+3: required string roleName,
+4: required set<string> requestorGroupName,
+5: 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 requestorUserName,
+3: required set<string> requestorGroupName
+}
+struct TAlterSentryRoleDeleteGroupsResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TAlterSentryRoleGrantPrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string requestorUserName,
+3: required string roleName,
+4: required set<string> requestorGroupName,
+5: required TSentryPrivilege privilege
+}
+
+struct TAlterSentryRoleGrantPrivilegeResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+struct TAlterSentryRoleRevokePrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1,
+2: required string requestorUserName,
+3: required string roleName,
+4: required set<string> requestorGroupName,
+5: required TSentryPrivilege privilege
+}
+
+struct TAlterSentryRoleRevokePrivilegeResponse {
+1: required sentry_common_service.TSentryResponseStatus status
+}
+
+service SentryPolicyService
+{
+ TCreateSentryRoleResponse create_sentry_role(1:TCreateSentryRoleRequest request)
+ TDropSentryRoleResponse drop_sentry_role(1:TDropSentryRoleRequest request)
+
+ TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege(1:TAlterSentryRoleGrantPrivilegeRequest request)
+ TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege(1:TAlterSentryRoleRevokePrivilegeRequest request)
+
+ TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(1:TAlterSentryRoleAddGroupsRequest request)
+ TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(1:TAlterSentryRoleDeleteGroupsRequest request)
+
+ TListSentryRolesResponse list_sentry_roles_by_group(1:TListSentryRolesRequest request)
+ TListSentryRolesResponse list_sentry_roles_by_role_name(1:TListSentryRolesRequest request)
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
new file mode 100644
index 0000000..be3d078
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
@@ -0,0 +1,145 @@
+/**
+ * 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.persistent;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryRole;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor;
+import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+
+public class TestSentryStore {
+
+ private static File dataDir;
+ private static SentryStore sentryStore;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ dataDir = new File(Files.createTempDir(), SentryStore.DEFAULT_DATA_DIR);
+ sentryStore = new SentryStore(dataDir.getPath());
+ }
+
+ @AfterClass
+ public static void teardown() {
+ if (sentryStore != null) {
+ sentryStore.stop();
+ }
+ if (dataDir != null) {
+ FileUtils.deleteQuietly(dataDir);
+ }
+ }
+
+ private static CommitContext createRole(String r, String g) throws Exception {
+ TSentryRole role = new TSentryRole();
+ role.setGrantorPrincipal(g);
+ role.setRoleName(r);
+ return sentryStore.createSentryRole(role);
+ }
+
+
+ @Test
+ public void testCreateDuplicateRole() throws Exception {
+ String roleName = "test-dup-role";
+ String grantor = "g1";
+ createRole(roleName, grantor);
+ try {
+ createRole(roleName, grantor);
+ fail("Expected SentryAlreadyExistsException");
+ } catch(SentryAlreadyExistsException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testCreateDropRole() throws Exception {
+ String roleName = "test-drop-role";
+ String grantor = "g1";
+ long seqId = createRole(roleName, grantor).getSequenceId();
+ assertEquals(seqId + 1, sentryStore.dropSentryRole(roleName).getSequenceId());
+ }
+
+ @Test(expected = SentryNoSuchObjectException.class)
+ public void testAddDeleteGroupsNonExistantRole()
+ throws Exception {
+ String roleName = "non-existant-role";
+ String grantor = "g1";
+ Set<TSentryGroup> groups = Sets.newHashSet();
+ sentryStore.alterSentryRoleAddGroups(grantor, roleName, groups);
+ }
+
+ @Test
+ public void testAddDeleteGroups() throws Exception {
+ String roleName = "test-groups";
+ String grantor = "g1";
+ long seqId = createRole(roleName, grantor).getSequenceId();
+ Set<TSentryGroup> groups = Sets.newHashSet();
+ TSentryGroup group = new TSentryGroup();
+ group.setGroupName("test-groups-g1");
+ groups.add(group);
+ group = new TSentryGroup();
+ group.setGroupName("test-groups-g2");
+ groups.add(group);
+ assertEquals(seqId + 1, sentryStore.alterSentryRoleAddGroups(grantor,
+ roleName, groups).getSequenceId());
+ assertEquals(seqId + 2, sentryStore.alterSentryRoleDeleteGroups(roleName, groups)
+ .getSequenceId());
+ MSentryRole role = sentryStore.getMSentryRoleByName(roleName);
+ assertEquals(Collections.emptySet(), role.getGroups());
+ }
+
+ @Test
+ public void testGrantRevokePrivilege() throws Exception {
+ String roleName = "test-privilege";
+ String grantor = "g1";
+ long seqId = createRole(roleName, grantor).getSequenceId();
+ TSentryPrivilege privilege = new TSentryPrivilege();
+ privilege.setPrivilegeScope("TABLE");
+ privilege.setServerName("server1");
+ privilege.setDbName("db1");
+ privilege.setTableName("tbl1");
+ privilege.setAction("SELECT");
+ privilege.setGrantorPrincipal(grantor);
+ privilege.setCreateTime(System.currentTimeMillis());
+ privilege.setPrivilegeName(SentryPolicyStoreProcessor.constructPrivilegeName(privilege));
+ assertEquals(seqId + 1, sentryStore.alterSentryRoleGrantPrivilege(roleName, privilege)
+ .getSequenceId());
+ MSentryRole role = sentryStore.getMSentryRoleByName(roleName);
+ Set<MSentryPrivilege> privileges = role.getPrivileges();
+ assertEquals(privileges.toString(), 1, privileges.size());
+ assertEquals(privilege.getPrivilegeName(), Iterables.get(privileges, 0).getPrivilegeName());
+ assertEquals(seqId + 2, sentryStore.alterSentryRoleRevokePrivilege(roleName, privilege.getPrivilegeName())
+ .getSequenceId());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestNotificationHandlerInvoker.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestNotificationHandlerInvoker.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestNotificationHandlerInvoker.java
new file mode 100644
index 0000000..6a2f48f
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestNotificationHandlerInvoker.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.service.thrift;
+
+import java.util.UUID;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.CommitContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.google.common.collect.Lists;
+
+public class TestNotificationHandlerInvoker {
+
+ private Configuration conf;
+ private CommitContext commitContext;
+ private NotificationHandler handler;
+ private NotificationHandlerInvoker invoker;
+
+ @Before
+ public void setup() throws Exception {
+ conf = new Configuration(false);
+ commitContext = new CommitContext(UUID.randomUUID(), 1L);
+ handler = Mockito.spy(new NotificationHandler(conf) {});
+ invoker = new NotificationHandlerInvoker(conf,
+ Lists.newArrayList(new ThrowingNotificationHandler(conf), handler));
+ }
+
+ @Test
+ public void testCreateSentryRole() throws Exception {
+ TCreateSentryRoleRequest request = new TCreateSentryRoleRequest();
+ TCreateSentryRoleResponse response = new TCreateSentryRoleResponse();
+ invoker.create_sentry_role(commitContext, request, response);
+ Mockito.verify(handler).create_sentry_role(commitContext,
+ request, response);
+ }
+
+ @Test
+ public void testDropSentryRole() throws Exception {
+ TDropSentryRoleRequest request = new TDropSentryRoleRequest();
+ TDropSentryRoleResponse response = new TDropSentryRoleResponse();
+ invoker.drop_sentry_role(commitContext, request, response);
+ Mockito.verify(handler).drop_sentry_role(commitContext,
+ request, response);
+ }
+
+
+
+ @Test
+ public void testAlterSentryRoleAddGroups() throws Exception {
+ TAlterSentryRoleAddGroupsRequest request = new TAlterSentryRoleAddGroupsRequest();
+ TAlterSentryRoleAddGroupsResponse response = new TAlterSentryRoleAddGroupsResponse();
+ invoker.alter_sentry_role_add_groups(commitContext, request, response);
+ Mockito.verify(handler).alter_sentry_role_add_groups(commitContext,
+ request, response);
+ }
+
+ @Test
+ public void testAlterSentryRoleDeleteGroups() throws Exception {
+ TAlterSentryRoleDeleteGroupsRequest request = new TAlterSentryRoleDeleteGroupsRequest();
+ TAlterSentryRoleDeleteGroupsResponse response = new TAlterSentryRoleDeleteGroupsResponse();
+ invoker.alter_sentry_role_delete_groups(commitContext, request, response);
+ Mockito.verify(handler).alter_sentry_role_delete_groups(commitContext,
+ request, response);
+ }
+
+ public static class ThrowingNotificationHandler extends NotificationHandler {
+ public ThrowingNotificationHandler(Configuration config) throws Exception {
+ super(config);
+ }
+ @Override
+ public void create_sentry_role(CommitContext args,
+ TCreateSentryRoleRequest request, TCreateSentryRoleResponse response) {
+ throw new RuntimeException();
+ }
+ public void drop_sentry_role(CommitContext context,
+ TDropSentryRoleRequest request,
+ TDropSentryRoleResponse response) {
+ throw new RuntimeException();
+ }
+ @Override
+ public void alter_sentry_role_add_groups(CommitContext args,
+ TAlterSentryRoleAddGroupsRequest request,
+ TAlterSentryRoleAddGroupsResponse response) {
+ throw new RuntimeException();
+ }
+ @Override
+ public void alter_sentry_role_delete_groups(
+ CommitContext args, TAlterSentryRoleDeleteGroupsRequest request,
+ TAlterSentryRoleDeleteGroupsResponse response) {
+ throw new RuntimeException();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryPolicyStoreProcessor.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryPolicyStoreProcessor.java
new file mode 100644
index 0000000..46f8fb8
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryPolicyStoreProcessor.java
@@ -0,0 +1,70 @@
+/**
+ * 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 junit.framework.Assert;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants.PolicyStoreServerConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestSentryPolicyStoreProcessor {
+
+ private Configuration conf;
+
+ @Before
+ public void setup() {
+ conf = new Configuration(false);
+ }
+ @Test(expected=SentryConfigurationException.class)
+ public void testConfigNotNotificationHandler() throws Exception {
+ conf.set(PolicyStoreServerConfig.NOTIFICATION_HANDLERS, Object.class.getName());
+ SentryPolicyStoreProcessor.createHandlers(conf);
+ }
+ @Test(expected=SentryConfigurationException.class)
+ public void testConfigCannotCreateNotificationHandler() throws Exception {
+ conf.set(PolicyStoreServerConfig.NOTIFICATION_HANDLERS,
+ ExceptionInConstructorNotificationHandler.class.getName());
+ SentryPolicyStoreProcessor.createHandlers(conf);
+ }
+ @Test(expected=SentryConfigurationException.class)
+ public void testConfigNotAClassNotificationHandler() throws Exception {
+ conf.set(PolicyStoreServerConfig.NOTIFICATION_HANDLERS, "junk");
+ SentryPolicyStoreProcessor.createHandlers(conf);
+ }
+ @Test
+ public void testConfigMultipleNotificationHandlers() throws Exception {
+ conf.set(PolicyStoreServerConfig.NOTIFICATION_HANDLERS,
+ NoopNotificationHandler.class.getName() + "," +
+ NoopNotificationHandler.class.getName() + " " +
+ NoopNotificationHandler.class.getName());
+ Assert.assertEquals(3, SentryPolicyStoreProcessor.createHandlers(conf).size());
+ }
+ public static class ExceptionInConstructorNotificationHandler extends NotificationHandler {
+ public ExceptionInConstructorNotificationHandler(Configuration config) throws Exception {
+ super(config);
+ throw new Exception();
+ }
+ }
+ public static class NoopNotificationHandler extends NotificationHandler {
+ public NoopNotificationHandler(Configuration config) throws Exception {
+ super(config);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
new file mode 100644
index 0000000..a4643bf
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceFailureCase.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless 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.security.PrivilegedActionException;
+
+import org.apache.sentry.service.thrift.SentryServiceIntegrationBase;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestSentryServiceFailureCase extends SentryServiceIntegrationBase {
+
+ @Before @Override
+ public void setup() throws Exception {
+ beforeSetup();
+ setupConf();
+ conf.set(ServerConfig.ALLOW_CONNECT, "");
+ startSentryService();
+ afterSetup();
+ }
+
+ @Test(expected = PrivilegedActionException.class)
+ public void testClientServerConnectionFailure() throws Exception {
+ connectToSentryService();
+ Assert.fail("Failed to receive Exception");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/644e8be3/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
new file mode 100644
index 0000000..d073d8b
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServiceIntegration.java
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless createRequired by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.service.thrift;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sentry.service.thrift.SentryServiceIntegrationBase;
+import org.apache.sentry.service.thrift.ServiceConstants.ThriftConstants;
+import org.apache.sentry.service.thrift.Status;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class TestSentryServiceIntegration extends SentryServiceIntegrationBase {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryServiceIntegration.class);
+
+ @Test
+ public void testCreateRole() throws Exception {
+ Set<String> groupSet = new HashSet<String>();
+ TDropSentryRoleRequest dropReq = new TDropSentryRoleRequest();
+ dropReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ dropReq.setRoleName("admin_r");
+ dropReq.setRequestorUserName("user_1");
+ groupSet.add("admin");
+ dropReq.setRequestorGroupName(groupSet);
+ TDropSentryRoleResponse dropResp = client.dropRole(dropReq);
+ assertStatus(Status.NO_SUCH_OBJECT, dropResp.getStatus());
+ LOGGER.info("Successfully dropped role: admin_r");
+ groupSet.clear();
+
+ TCreateSentryRoleRequest createReq = new TCreateSentryRoleRequest();
+ createReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ createReq.setRequestorUserName("user_1");
+ groupSet.add("admin");
+ createReq.setRequestorGroupName(groupSet);
+ TSentryRole role = new TSentryRole();
+ role.setRoleName("admin_r");
+ role.setCreateTime(System.currentTimeMillis());
+ role.setGrantorPrincipal("test");
+ role.setPrivileges(new HashSet<TSentryPrivilege>());
+ createReq.setRole(role);
+ TCreateSentryRoleResponse createResp = client.createRole(createReq);
+ assertOK(createResp.getStatus());
+ LOGGER.info("Successfully create role: admin_r");
+ groupSet.clear();
+
+ TListSentryRolesRequest listReq = new TListSentryRolesRequest();
+ listReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ listReq.setRoleName("admin_r");
+ listReq.setRequestorUserName("user_1");
+ groupSet.add("admin");
+ listReq.setRequestorGroupName(groupSet);
+ TListSentryRolesResponse listResp = client.listRoleByName(listReq);
+ Set<TSentryRole> roles = listResp.getRoles();
+ Preconditions.checkArgument(roles.size() == 1, "Incorrect number of roles");
+ groupSet.clear();
+
+ dropReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ dropReq.setRoleName("admin_r");
+ dropReq.setRequestorUserName("user_1");
+ groupSet.add("admin");
+ dropReq.setRequestorGroupName(groupSet);
+ dropResp = client.dropRole(dropReq);
+ assertOK(dropResp.getStatus());
+ LOGGER.info("Successfully dropped role: admin_r");
+ groupSet.clear();
+ }
+
+ @Test
+ public void testGrantRevokePrivilege() throws Exception {
+ Set<String> groupSet = new HashSet<String>();
+ TDropSentryRoleRequest dropReq = new TDropSentryRoleRequest();
+ dropReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ dropReq.setRoleName("admin_testdb");
+ dropReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ dropReq.setRequestorGroupName(groupSet);
+ TDropSentryRoleResponse dropResp = client.dropRole(dropReq);
+ assertStatus(Status.NO_SUCH_OBJECT, dropResp.getStatus());
+ LOGGER.info("Successfully dropped role: admin_testdb");
+ groupSet.clear();
+
+ TCreateSentryRoleRequest createReq = new TCreateSentryRoleRequest();
+ createReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ createReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ createReq.setRequestorGroupName(groupSet);
+ TSentryRole role = new TSentryRole();
+ role.setRoleName("admin_testdb");
+ role.setCreateTime(System.currentTimeMillis());
+ role.setGrantorPrincipal("server_admin");
+ role.setPrivileges(new HashSet<TSentryPrivilege>());
+ createReq.setRole(role);
+ TCreateSentryRoleResponse createResp = client.createRole(createReq);
+ assertOK(createResp.getStatus());
+ LOGGER.info("Successfully create role: admin_testdb");
+ groupSet.clear();
+
+ TListSentryRolesRequest listReq = new TListSentryRolesRequest();
+ listReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ listReq.setRoleName("admin_testdb");
+ listReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ listReq.setRequestorGroupName(groupSet);
+ TListSentryRolesResponse listResp = client.listRoleByName(listReq);
+ Set<TSentryRole> roles = listResp.getRoles();
+ Preconditions.checkArgument(roles.size() == 1, "Incorrect number of roles");
+ groupSet.clear();
+
+ TAlterSentryRoleGrantPrivilegeRequest grantReq = new TAlterSentryRoleGrantPrivilegeRequest();
+ grantReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ grantReq.setRoleName("admin_testdb");
+ grantReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ grantReq.setRequestorGroupName(groupSet);
+ TSentryPrivilege privilege = new TSentryPrivilege();
+ privilege.setPrivilegeScope("DB");
+ privilege.setServerName("server1");
+ privilege.setDbName("testDB");
+ privilege.setAction("ALL");
+ privilege.setGrantorPrincipal("server_admin");
+ privilege.setCreateTime(System.currentTimeMillis());
+ grantReq.setPrivilege(privilege);
+ TAlterSentryRoleGrantPrivilegeResponse grantResp = client.grantPrivilege(grantReq);
+ assertOK(grantResp.getStatus());
+ LOGGER.info("Successfully granted privilege: " + privilege.toString());
+ groupSet.clear();
+
+ TAlterSentryRoleRevokePrivilegeRequest revokeReq = new TAlterSentryRoleRevokePrivilegeRequest();
+ revokeReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ revokeReq.setRoleName("admin_testdb");
+ revokeReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ revokeReq.setRequestorGroupName(groupSet);
+ revokeReq.setPrivilege(privilege);
+ TAlterSentryRoleRevokePrivilegeResponse revokeResp = client.revokePrivilege(revokeReq);
+ assertOK(revokeResp.getStatus());
+ LOGGER.info("Successfully revoked privilege: " + privilege.toString());
+ groupSet.clear();
+
+ dropReq.setProtocol_version(ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT);
+ dropReq.setRoleName("admin_testdb");
+ dropReq.setRequestorUserName("server_admin");
+ groupSet.add("admin");
+ dropReq.setRequestorGroupName(groupSet);
+ dropResp = client.dropRole(dropReq);
+ assertOK(dropResp.getStatus());
+ LOGGER.info("Successfully dropped role: admin_testdb");
+ groupSet.clear();
+ }
+
+}