You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by gq...@apache.org on 2015/02/25 03:09:24 UTC

incubator-sentry git commit: SENTRY-478: Solr Sentry plug-in integration with DB store (Guoquan Shen, reviewed by Lenni Kuff)

Repository: incubator-sentry
Updated Branches:
  refs/heads/master 603ca8998 -> 3893e22dd


SENTRY-478: Solr Sentry plug-in integration with DB store (Guoquan Shen, reviewed by Lenni Kuff)


Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/3893e22d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/3893e22d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/3893e22d

Branch: refs/heads/master
Commit: 3893e22dd879542419fd9da81fe548361f0821db
Parents: 603ca89
Author: Guoquan Shen <gu...@intel.com>
Authored: Wed Feb 25 09:47:17 2015 +0800
Committer: Guoquan Shen <gu...@intel.com>
Committed: Wed Feb 25 09:47:17 2015 +0800

----------------------------------------------------------------------
 sentry-binding/sentry-binding-solr/pom.xml      |   4 +
 .../binding/solr/authz/SolrAuthzBinding.java    |  46 ++++
 .../core/model/search/SearchConstants.java      |   8 +-
 .../policy/search/SimpleSearchPolicyEngine.java |   2 +-
 .../provider/common/AuthorizationComponent.java |  24 ++
 .../thrift/SearchPolicyServiceClient.java       | 159 +++++++++++
 .../service/thrift/SearchProviderBackend.java   | 141 ++++++++++
 .../solr/handler/SecureRequestHandlerUtil.java  |  12 +
 .../handler/admin/SecureCollectionsHandler.java |  10 +
 .../SentryIndexAuthorizationSingleton.java      |  13 +
 sentry-tests/sentry-tests-solr/pom.xml          |   5 +
 .../e2e/solr/AbstractSolrSentryTestBase.java    |  41 ++-
 .../AbstractSolrSentryTestWithDbProvider.java   | 275 +++++++++++++++++++
 .../db/integration/TestSolrAdminOperations.java | 236 ++++++++++++++++
 .../integration/TestSolrDocLevelOperations.java | 204 ++++++++++++++
 .../db/integration/TestSolrQueryOperations.java |  96 +++++++
 .../integration/TestSolrUpdateOperations.java   | 105 +++++++
 17 files changed, 1356 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-binding/sentry-binding-solr/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/pom.xml b/sentry-binding/sentry-binding-solr/pom.xml
index b3329e2..4e785e7 100644
--- a/sentry-binding/sentry-binding-solr/pom.xml
+++ b/sentry-binding/sentry-binding-solr/pom.xml
@@ -48,6 +48,10 @@ limitations under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.sentry</groupId>
+      <artifactId>sentry-provider-db</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sentry</groupId>
       <artifactId>sentry-provider-file</artifactId>
       <scope>test</scope>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
index a43a1e0..373ee8c 100644
--- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
@@ -26,6 +26,7 @@ import org.apache.hadoop.conf.Configuration;
 import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.SentryUserException;
 import org.apache.sentry.binding.solr.conf.SolrAuthzConf;
 import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars;
 import org.apache.sentry.core.common.ActiveRoleSet;
@@ -36,6 +37,8 @@ import org.apache.sentry.policy.common.PolicyEngine;
 import org.apache.sentry.provider.common.AuthorizationProvider;
 import org.apache.sentry.provider.common.GroupMappingService;
 import org.apache.sentry.provider.common.ProviderBackend;
+import org.apache.sentry.provider.db.generic.service.thrift.SearchPolicyServiceClient;
+import org.apache.sentry.provider.db.generic.service.thrift.SearchProviderBackend;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,11 +61,17 @@ public class SolrAuthzBinding {
   private final AuthorizationProvider authProvider;
   private final GroupMappingService groupMapping;
   private ProviderBackend providerBackend;
+  private Subject bindingSubject;
 
   public SolrAuthzBinding (SolrAuthzConf authzConf) throws Exception {
     this.authzConf = addHdfsPropsToConf(authzConf);
     this.authProvider = getAuthProvider();
     this.groupMapping = authProvider.getGroupMapping();
+    /**
+     * The Solr server principal will use the binding
+     */
+    this.bindingSubject = new Subject(UserGroupInformation.getCurrentUser()
+        .getShortUserName());
   }
 
   // Instantiate the configured authz provider
@@ -206,4 +215,41 @@ public class SolrAuthzBinding {
       }
     }
   }
+
+  /**
+   * SENTRY-478
+   * If the binding uses the searchProviderBackend, it can sync privilege with Sentry Service
+   */
+  public boolean isSyncEnabled() {
+    return (providerBackend instanceof SearchProviderBackend);
+  }
+
+  public SearchPolicyServiceClient getClient() throws Exception {
+    return new SearchPolicyServiceClient(authzConf);
+  }
+
+  /**
+   * Attempt to notify the Sentry service when deleting collection happened
+   * @param collection
+   * @throws SolrException
+   */
+  public void deleteCollectionPrivilege(String collection) throws SentrySolrAuthorizationException {
+    if (!isSyncEnabled()) {
+      return;
+    }
+    SearchPolicyServiceClient client = null;
+    try {
+      client = getClient();
+      client.dropCollectionPrivilege(collection, bindingSubject.getName());
+    } catch (SentryUserException ex) {
+      throw new SentrySolrAuthorizationException("User " + bindingSubject.getName() +
+          " can't delete privileges for collection " + collection);
+    } catch (Exception ex) {
+      throw new SentrySolrAuthorizationException("Unable to obtain client:" + ex.getMessage());
+    } finally {
+      if (client != null) {
+        client.close();
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-core/sentry-core-model-search/src/main/java/org/apache/sentry/core/model/search/SearchConstants.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-model-search/src/main/java/org/apache/sentry/core/model/search/SearchConstants.java b/sentry-core/sentry-core-model-search/src/main/java/org/apache/sentry/core/model/search/SearchConstants.java
index 7a39b79..16b9195 100644
--- a/sentry-core/sentry-core-model-search/src/main/java/org/apache/sentry/core/model/search/SearchConstants.java
+++ b/sentry-core/sentry-core-model-search/src/main/java/org/apache/sentry/core/model/search/SearchConstants.java
@@ -21,5 +21,11 @@ public class SearchConstants {
   public static final String ALL = "*";
   public static final String QUERY = "query";
   public static final String UPDATE = "update";
-
+  /**
+   * The property of sentry.search.cluster was used to distinguish itself from multiple search clusters. For example, there are two
+   * search clusters: cluster1 and cluster2 implemented authorization via sentry, and it must set the value of
+   * sentry.search.cluster=cluster1 or cluster2 to communicate with sentry service for authorization
+   */
+  public static final String SENTRY_SEARCH_CLUSTER_KEY = "sentry.search.cluster";
+  public static final String SENTRY_SEARCH_CLUSTER_DEFAULT = "clutser1";
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java b/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
index f428aea..bc518fb 100644
--- a/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
+++ b/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
@@ -85,7 +85,7 @@ public class SimpleSearchPolicyEngine implements PolicyEngine {
   @Override
   public void validatePolicy(boolean strictValidation)
       throws SentryConfigurationException {
-    throw new SentryConfigurationException("Not implemented yet");
+    providerBackend.validatePolicy(strictValidation);
   }
 
   public static ImmutableList<PrivilegeValidator> createPrivilegeValidators() {

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationComponent.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationComponent.java b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationComponent.java
new file mode 100644
index 0000000..def3486
--- /dev/null
+++ b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationComponent.java
@@ -0,0 +1,24 @@
+/*
+ * 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.common;
+/**
+ * Represent which component being authorized by Sentry
+ * using generic model
+ */
+public class AuthorizationComponent{
+  public static final String Search = "solr";
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchPolicyServiceClient.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchPolicyServiceClient.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchPolicyServiceClient.java
new file mode 100644
index 0000000..1ed3fcd
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchPolicyServiceClient.java
@@ -0,0 +1,159 @@
+/**
+ * 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.generic.service.thrift;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.SentryUserException;
+import org.apache.sentry.core.common.Action;
+import org.apache.sentry.core.common.ActiveRoleSet;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.provider.common.AuthorizationComponent;
+
+import com.google.common.collect.Lists;
+
+import static org.apache.sentry.core.model.search.SearchModelAuthorizable.AuthorizableType.Collection;
+import static org.apache.sentry.core.model.search.SearchConstants.SENTRY_SEARCH_CLUSTER_KEY;
+import static org.apache.sentry.core.model.search.SearchConstants.SENTRY_SEARCH_CLUSTER_DEFAULT;
+
+/**
+ * This search policy client will be used in the solr component to communicate with Sentry service.
+ *
+ */
+public class SearchPolicyServiceClient {
+  private static final String COMPONENT_TYPE = AuthorizationComponent.Search;
+
+  private String searchClusterName;
+  private SentryGenericServiceClient client;
+
+  public SearchPolicyServiceClient(Configuration conf) throws Exception {
+    this.searchClusterName = conf.get(SENTRY_SEARCH_CLUSTER_KEY, SENTRY_SEARCH_CLUSTER_DEFAULT);
+    this.client = new SentryGenericServiceClient(conf);
+  }
+
+  public void createRole(final String requestor, final String roleName)
+      throws SentryUserException {
+    client.createRole(requestor, roleName, COMPONENT_TYPE);
+  }
+
+  public void createRoleIfNotExist(final String requestor,
+      final String roleName) throws SentryUserException {
+    client.createRoleIfNotExist(requestor, roleName, COMPONENT_TYPE);
+  }
+
+  public void dropRole(final String requestor, final String roleName)
+      throws SentryUserException {
+    client.dropRole(requestor, roleName, COMPONENT_TYPE);
+  }
+
+  public void dropRoleIfExists(final String requestor, final String roleName)
+      throws SentryUserException {
+    client.dropRoleIfExists(requestor, roleName, COMPONENT_TYPE);
+  }
+
+  public void addRoleToGroups(final String requestor, final String roleName,
+      final Set<String> groups) throws SentryUserException {
+    client.addRoleToGroups(requestor, roleName, COMPONENT_TYPE, groups);
+  }
+
+  public void deleteRoleFromGroups(final String requestor, final String roleName,
+      final Set<String> groups) throws SentryUserException {
+    client.deleteRoleToGroups(requestor, roleName, COMPONENT_TYPE, groups);
+  }
+
+  public void grantCollectionPrivilege(final String collection, final String requestor,
+      final String roleName,final String action) throws SentryUserException {
+    grantCollectionPrivilege(collection, requestor, roleName, action, false);
+  }
+
+  public void grantCollectionPrivilege(final String collection, final String requestor,
+      final String roleName, final String action, final Boolean grantOption) throws SentryUserException {
+    TSentryPrivilege tPrivilege = toTSentryPrivilege(collection, action, grantOption);
+    client.grantPrivilege(requestor, roleName, COMPONENT_TYPE, tPrivilege);
+  }
+
+  public void revokeCollectionPrivilege(final String collection, final String requestor, final String roleName,
+      final String action) throws SentryUserException {
+    revokeCollectionPrivilege(collection, requestor, roleName, action, false);
+  }
+
+  public void revokeCollectionPrivilege(final String collection, final String requestor, final String roleName,
+      final String action, final Boolean grantOption) throws SentryUserException {
+    TSentryPrivilege tPrivilege = toTSentryPrivilege(collection, action, grantOption);
+    client.revokePrivilege(requestor, roleName, COMPONENT_TYPE, tPrivilege);
+  }
+
+  public void renameCollectionPrivilege(final String oldCollection, final String newCollection, final String requestor)
+      throws SentryUserException {
+    client.renamePrivilege(requestor, COMPONENT_TYPE, searchClusterName, Lists.newArrayList(new Collection(oldCollection)),
+        Lists.newArrayList(new Collection(newCollection)));
+  }
+
+  public void dropCollectionPrivilege(final String collection, final String requestor) throws SentryUserException {
+    final TSentryPrivilege tPrivilege = toTSentryPrivilege(collection, Action.ALL, null);
+    client.dropPrivilege(requestor, COMPONENT_TYPE, tPrivilege);
+  }
+
+  public Set<TSentryRole> listAllRoles(final String user) throws SentryUserException {
+    return client.listAllRoles(user, COMPONENT_TYPE);
+  }
+
+  public Set<TSentryRole> listRolesByGroupName(final String requestor, final String groupName) throws SentryUserException {
+    return client.listRolesByGroupName(requestor, groupName, COMPONENT_TYPE);
+  }
+
+  public Set<TSentryPrivilege> listPrivilegesByRoleName(
+      final String requestor, final String roleName,
+      final List<? extends Authorizable> authorizables) throws SentryUserException {
+    return client.listPrivilegesByRoleName(requestor, roleName, COMPONENT_TYPE, searchClusterName, authorizables);
+  }
+
+  public Set<String> listPrivilegesForProvider(final ActiveRoleSet roleSet, final Set<String> groups,
+      final List<? extends Authorizable> authorizables) throws SentryUserException {
+    return client.listPrivilegesForProvider(COMPONENT_TYPE, searchClusterName, roleSet, groups, authorizables);
+  }
+
+  private TSentryPrivilege toTSentryPrivilege(String collection, String action,
+      Boolean grantOption) {
+    TSentryPrivilege tPrivilege = new TSentryPrivilege();
+    tPrivilege.setComponent(COMPONENT_TYPE);
+    tPrivilege.setServiceName(searchClusterName);
+    tPrivilege.setAction(action);
+
+    if (grantOption == null) {
+      tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+    } else if (grantOption) {
+      tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+    } else {
+      tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+    }
+
+    List<TAuthorizable> authorizables = Lists.newArrayList(new TAuthorizable(Collection.name(), collection));
+    tPrivilege.setAuthorizables(authorizables);
+    return tPrivilege;
+  }
+
+  public void close() {
+    if (client != null) {
+      client.close();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchProviderBackend.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchProviderBackend.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchProviderBackend.java
new file mode 100644
index 0000000..ae324bf
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SearchProviderBackend.java
@@ -0,0 +1,141 @@
+/**
+ * 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.generic.service.thrift;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.SentryUserException;
+import org.apache.sentry.core.common.ActiveRoleSet;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
+import org.apache.sentry.core.common.Subject;
+import org.apache.sentry.provider.common.ProviderBackend;
+import org.apache.sentry.provider.common.ProviderBackendContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+/**
+ * when Solr integration with Database store, this backend will communicate with Sentry service to get
+ * privileges according to the requested groups
+ *
+ */
+public class SearchProviderBackend implements ProviderBackend {
+  private static final Logger LOGGER = LoggerFactory.getLogger(SearchProviderBackend.class);
+  private final Configuration conf;
+  private final Subject subject;
+  private volatile boolean initialized = false;
+
+  public SearchProviderBackend(Configuration conf, String resourcePath) throws Exception {
+    this.conf = conf;
+    /**
+     * Who create the searchProviderBackend, this subject will been used the requester to communicate
+     * with Sentry Service
+     */
+    subject = new Subject(UserGroupInformation.getCurrentUser()
+        .getShortUserName());
+  }
+
+  @Override
+  public void initialize(ProviderBackendContext context) {
+    if (initialized) {
+      throw new IllegalStateException("SearchProviderBackend has already been initialized, cannot be initialized twice");
+    }
+    this.initialized = true;
+  }
+
+  @Override
+  public ImmutableSet<String> getPrivileges(Set<String> groups,
+      ActiveRoleSet roleSet, Authorizable... authorizableHierarchy) {
+    if (!initialized) {
+      throw new IllegalStateException("SearchProviderBackend has not been properly initialized");
+    }
+    SearchPolicyServiceClient client = null;
+    try {
+      client = getClient();
+      return ImmutableSet.copyOf(client.listPrivilegesForProvider(roleSet, groups, Arrays.asList(authorizableHierarchy)));
+    } catch (SentryUserException e) {
+      String msg = "Unable to obtain privileges from server: " + e.getMessage();
+      LOGGER.error(msg, e);
+    } catch (Exception e) {
+      String msg = "Unable to obtain client:" + e.getMessage();
+      LOGGER.error(msg, e);
+    } finally {
+      if (client != null) {
+        client.close();
+      }
+    }
+    return ImmutableSet.of();
+  }
+
+  @Override
+  public ImmutableSet<String> getRoles(Set<String> groups, ActiveRoleSet roleSet) {
+    if (!initialized) {
+      throw new IllegalStateException("SearchProviderBackend has not been properly initialized");
+    }
+    SearchPolicyServiceClient client = null;
+    try {
+      Set<TSentryRole> tRoles = Sets.newHashSet();
+      client = getClient();
+      //get the roles according to group
+      for (String group : groups) {
+        tRoles.addAll(client.listRolesByGroupName(subject.getName(), group));
+      }
+      Set<String> roles = Sets.newHashSet();
+      for (TSentryRole tRole : tRoles) {
+        roles.add(tRole.getRoleName());
+      }
+      return ImmutableSet.copyOf(roleSet.isAll() ? roles : Sets.intersection(roles, roleSet.getRoles()));
+    } catch (SentryUserException e) {
+      String msg = "Unable to obtain roles from server: " + e.getMessage();
+      LOGGER.error(msg, e);
+    } catch (Exception e) {
+      String msg = "Unable to obtain client:" + e.getMessage();
+      LOGGER.error(msg, e);
+    } finally {
+      if (client != null) {
+        client.close();
+      }
+    }
+    return ImmutableSet.of();
+  }
+
+  public SearchPolicyServiceClient getClient() throws Exception {
+    return new SearchPolicyServiceClient(conf);
+  }
+
+  /**
+   * SearchProviderBackend does nothing in the validatePolicy()
+   */
+  @Override
+  public void validatePolicy(boolean strictValidation)
+      throws SentryConfigurationException {
+    if (!initialized) {
+      throw new IllegalStateException("Backend has not been properly initialized");
+    }
+  }
+
+  @Override
+  public void close() {
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/SecureRequestHandlerUtil.java
----------------------------------------------------------------------
diff --git a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/SecureRequestHandlerUtil.java b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/SecureRequestHandlerUtil.java
index 8b46388..7ae5391 100644
--- a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/SecureRequestHandlerUtil.java
+++ b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/SecureRequestHandlerUtil.java
@@ -55,6 +55,18 @@ public class SecureRequestHandlerUtil {
     checkSentry(req, andActions, false, false, null);
   }
 
+  /**
+   * Attempt to sync collection privileges with Sentry when the metadata has changed.
+   * ex: When the collection has been deleted, the privileges related to the collection
+   * were also needed to drop. When the collection has been renamed, the privileges must been
+   * renamed too.
+   */
+  public static void syncDeleteCollection(String collection) {
+    final SentryIndexAuthorizationSingleton sentryInstance =
+        (testOverride == null)?SentryIndexAuthorizationSingleton.getInstance():testOverride;
+    sentryInstance.deleteCollection(collection);
+  }
+
   private static void checkSentry(SolrQueryRequest req, Set<SearchModelAction> andActions,
       boolean admin, boolean checkCollection, String collection) {
     // Sentry currently does have AND support for actions; need to check

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/admin/SecureCollectionsHandler.java
----------------------------------------------------------------------
diff --git a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/admin/SecureCollectionsHandler.java b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/admin/SecureCollectionsHandler.java
index 20d9626..0a471a4 100644
--- a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/admin/SecureCollectionsHandler.java
+++ b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/handler/admin/SecureCollectionsHandler.java
@@ -77,5 +77,15 @@ public class SecureCollectionsHandler extends CollectionsHandler {
     SecureRequestHandlerUtil.checkSentryAdmin(req, SecureRequestHandlerUtil.UPDATE_ONLY,
       true, collection);
     super.handleRequestBody(req, rsp);
+
+    /**
+     * Attempt to sync collection privileges with Sentry when the metadata has changed.
+     * ex: When the collection has been deleted, the privileges related to the collection
+     * were also needed to drop.
+     */
+    if (action.equals(CollectionAction.DELETE)) {
+      SecureRequestHandlerUtil.syncDeleteCollection(collection);
+    }
+
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/sentry/SentryIndexAuthorizationSingleton.java
----------------------------------------------------------------------
diff --git a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/sentry/SentryIndexAuthorizationSingleton.java b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/sentry/SentryIndexAuthorizationSingleton.java
index d44b228..53c8946 100644
--- a/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/sentry/SentryIndexAuthorizationSingleton.java
+++ b/sentry-solr/solr-sentry-handlers/src/main/java/org/apache/solr/sentry/SentryIndexAuthorizationSingleton.java
@@ -190,4 +190,17 @@ public class SentryIndexAuthorizationSingleton {
     return req instanceof LocalSolrQueryRequest?
       superUser:(String)httpServletRequest.getAttribute(USER_NAME);
   }
+
+  /**
+   * Attempt to notify the Sentry service when deleting collection happened
+   * @param collection
+   * @throws SolrException
+   */
+  public void deleteCollection(String collection) throws SolrException {
+    try {
+      binding.deleteCollectionPrivilege(collection);
+    } catch (SentrySolrAuthorizationException ex) {
+      throw new SolrException(SolrException.ErrorCode.UNAUTHORIZED, ex);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/pom.xml b/sentry-tests/sentry-tests-solr/pom.xml
index 12fea7c..5a1e5c2 100644
--- a/sentry-tests/sentry-tests-solr/pom.xml
+++ b/sentry-tests/sentry-tests-solr/pom.xml
@@ -44,6 +44,11 @@ limitations under the License.
       <artifactId>solr-sentry-handlers</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.sentry</groupId>
+      <artifactId>sentry-provider-db</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.solr</groupId>
       <artifactId>solr-solrj</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/AbstractSolrSentryTestBase.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/AbstractSolrSentryTestBase.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/AbstractSolrSentryTestBase.java
index ea2b12f..2495a9e 100644
--- a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/AbstractSolrSentryTestBase.java
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/AbstractSolrSentryTestBase.java
@@ -16,13 +16,17 @@
  */
 package org.apache.sentry.tests.e2e.solr;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.Map;
 import java.util.Random;
@@ -30,9 +34,11 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
-import com.google.common.io.Files;
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
@@ -44,33 +50,20 @@ import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.util.EntityUtils;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.hdfs.MiniDFSCluster;
 import org.apache.sentry.binding.solr.HdfsTestUtil;
 import org.apache.solr.client.solrj.SolrQuery;
-import org.apache.solr.client.solrj.SolrServer;
 import org.apache.solr.client.solrj.impl.CloudSolrServer;
-import org.apache.solr.client.solrj.impl.HttpSolrServer;
 import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.client.solrj.util.ClientUtils;
-import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
-import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.cloud.MiniSolrCloudCluster;
 import org.apache.solr.cloud.ZkController;
-import org.apache.solr.common.cloud.Replica;
-import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CollectionParams.CollectionAction;
 import org.apache.solr.common.params.CoreAdminParams;
@@ -84,18 +77,20 @@ import org.junit.BeforeClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.io.Files;
+
 public class AbstractSolrSentryTestBase {
   private static final Logger LOG = LoggerFactory.getLogger(AbstractSolrSentryTestBase.class);
   protected static final String SENTRY_ERROR_MSG = "SentrySolrAuthorizationException";
-  private static MiniDFSCluster dfsCluster;
-  private static MiniSolrCloudCluster miniSolrCloudCluster;
-  private static SortedMap<Class, String> extraRequestFilters;
+  protected static MiniDFSCluster dfsCluster;
+  protected static MiniSolrCloudCluster miniSolrCloudCluster;
+  protected static SortedMap<Class, String> extraRequestFilters;
   protected static final String ADMIN_USER = "admin";
   protected static final String ALL_DOCS = "*:*";
   protected static final Random RANDOM = new Random();
   protected static final String RESOURCES_DIR = "target" + File.separator + "test-classes" + File.separator + "solr";
   protected static final String CONF_DIR_IN_ZK = "conf1";
-  private static final int NUM_SERVERS = 4;
+  protected static final int NUM_SERVERS = 4;
 
   private static void addPropertyToSentry(StringBuilder builder, String name, String value) {
     builder.append("<property>\n");

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/AbstractSolrSentryTestWithDbProvider.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/AbstractSolrSentryTestWithDbProvider.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/AbstractSolrSentryTestWithDbProvider.java
new file mode 100644
index 0000000..9438ee5
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/AbstractSolrSentryTestWithDbProvider.java
@@ -0,0 +1,275 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.solr.db.integration;
+
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Comparator;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.binding.solr.HdfsTestUtil;
+import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars;
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.sentry.provider.common.AuthorizationComponent;
+import org.apache.sentry.provider.db.generic.service.thrift.SearchPolicyServiceClient;
+import org.apache.sentry.provider.db.generic.service.thrift.SearchProviderBackend;
+import org.apache.sentry.provider.file.LocalGroupResourceAuthorizationProvider;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.SentryService;
+import org.apache.sentry.service.thrift.SentryServiceFactory;
+import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.tests.e2e.solr.AbstractSolrSentryTestBase;
+import org.apache.sentry.tests.e2e.solr.ModifiableUserAuthenticationFilter;
+import org.apache.solr.cloud.MiniSolrCloudCluster;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+/**
+ * This class used to test the Solr integration with DB store.
+ * It will set up a miniSolrCloud, miniHDFS and Sentry service in a JVM process.
+ */
+public class AbstractSolrSentryTestWithDbProvider extends AbstractSolrSentryTestBase{
+  private static final Logger LOGGER = LoggerFactory
+      .getLogger(AbstractSolrSentryTestWithDbProvider.class);
+
+  protected static final String SERVER_HOST = NetUtils
+      .createSocketAddr("localhost:80").getAddress().getCanonicalHostName();
+  protected static final int PORT = 8038;
+  protected static final String ADMIN_GROUP = "admin_group";
+  protected static final String ADMIN_ROLE  = "admin_role";
+  protected static final String ADMIN_COLLECTION_NAME = "admin";
+
+  protected static final Configuration conf = new Configuration(false);
+
+  protected static SentryService server;
+  protected static SearchPolicyServiceClient client;
+
+  protected static File baseDir;
+  protected static File hdfsDir;
+  protected static File dbDir;
+  protected static File policyFilePath;
+  protected static File sentrySitePath;
+
+  protected static PolicyFile policyFile;
+
+  /**
+   * Overwrite the method from super class AbstractSolrSentryTestBase
+   * take over the management of miniSolrCloudCluster and dfsCluster
+   */
+  @BeforeClass
+  public static void beforeTestSimpleSolrEndToEnd() throws Exception {
+    setupConf();
+    startHDFS();
+    startSolrWithDbProvider();
+    startSentryService();
+    connectToSentryService();
+    setGroupsAndRoles();
+  }
+
+  @AfterClass
+  public static void teardownClass() throws Exception {
+    stopAllService();
+    FileUtils.deleteDirectory(baseDir);
+    unsetSystemProperties();
+  }
+
+  public static void setupConf() throws Exception {
+    baseDir = createTempDir();
+    hdfsDir = new File(baseDir, "hdfs");
+    dbDir = new File(baseDir, "sentry_policy_db");
+    policyFilePath = new File(baseDir, "local_policy_file.ini");
+    sentrySitePath = new File(baseDir, "sentry-site.xml");
+    policyFile = new PolicyFile();
+
+    conf.set(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_NONE);
+    conf.set(ServerConfig.SENTRY_VERIFY_SCHEM_VERSION, "false");
+    conf.set(ServerConfig.ADMIN_GROUPS, ADMIN_GROUP + ",solr");
+    conf.set(ServerConfig.RPC_ADDRESS, SERVER_HOST);
+    conf.set(ServerConfig.RPC_PORT, String.valueOf(PORT));
+    conf.set(ServerConfig.SENTRY_STORE_JDBC_URL,
+        "jdbc:derby:;databaseName=" + dbDir.getPath() + ";create=true");
+    conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE,
+        policyFilePath.getPath());
+    server = new SentryServiceFactory().create(conf);
+
+    conf.set(ClientConfig.SERVER_RPC_ADDRESS, server.getAddress().getHostName());
+    conf.set(ClientConfig.SERVER_RPC_PORT, String.valueOf(server.getAddress().getPort()));
+    conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING,
+        ServerConfig.SENTRY_STORE_LOCAL_GROUP_MAPPING);
+    conf.set(AuthzConfVars.AUTHZ_PROVIDER.getVar(),
+        LocalGroupResourceAuthorizationProvider.class.getName());
+    conf.set(AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar(), SearchProviderBackend.class.getName());
+    conf.set(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar(), policyFilePath.getPath());
+  }
+
+  public static File createTempDir() {
+    File baseDir = new File(System.getProperty("java.io.tmpdir"));
+    String baseName = "solr-integration-db-";
+    File tempDir = new File(baseDir, baseName + UUID.randomUUID().toString());
+    if (tempDir.mkdir()) {
+        return tempDir;
+    }
+    throw new IllegalStateException("Failed to create temp directory");
+  }
+
+  public static void configureWithSolr() throws Exception {
+    conf.set(ServerConfig.SECURITY_USE_UGI_TRANSPORT, "true");
+    //save configuration to sentry-site.xml
+    conf.writeXml(new FileOutputStream(sentrySitePath));
+    setSystemProperties();
+    extraRequestFilters = new TreeMap<Class, String>(new Comparator<Class>() {
+      // There's only one class, make this as simple as possible
+      @Override
+      public int compare(Class o1, Class o2) {
+        return 0;
+      }
+      @Override
+      public boolean equals(Object obj) {
+        return true;
+      }
+    });
+    extraRequestFilters.put(ModifiableUserAuthenticationFilter.class, "*");
+
+    //set the solr for the loginUser and belongs to solr group
+    addGroupsToUser("solr", "solr");
+    UserGroupInformation.setLoginUser(UserGroupInformation.createUserForTesting("solr", new String[]{"solr"}));
+  }
+
+  public static void startHDFS() throws Exception {
+    dfsCluster = HdfsTestUtil.setupClass(hdfsDir.getPath());
+    conf.set(
+        CommonConfigurationKeys.FS_DEFAULT_NAME_KEY,
+        dfsCluster.getFileSystem().getConf()
+        .get(CommonConfigurationKeys.FS_DEFAULT_NAME_KEY));
+  }
+
+  public static void startSolrWithDbProvider() throws Exception {
+    LOGGER.info("starting Solr authorization via Sentry Service");
+    configureWithSolr();
+    miniSolrCloudCluster = new MiniSolrCloudCluster(NUM_SERVERS, null,
+        new File(RESOURCES_DIR, "solr-no-core.xml"), null, extraRequestFilters);
+  }
+
+  public static 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 static void connectToSentryService() throws Exception {
+    client = new SearchPolicyServiceClient(conf);
+  }
+
+  public static void stopAllService() throws Exception {
+    if (miniSolrCloudCluster != null) {
+      miniSolrCloudCluster.shutdown();
+      miniSolrCloudCluster = null;
+    }
+    if (dfsCluster != null) {
+      HdfsTestUtil.teardownClass(dfsCluster);
+      dfsCluster = null;
+    }
+    if (client != null) {
+      client.close();
+      client = null;
+    }
+    if (server != null) {
+      server.stop();
+      server = null;
+    }
+  }
+
+  public static void addGroupsToUser(String user, String... groupNames) {
+    policyFile.addGroupsToUser(user, groupNames);
+  }
+
+  public static void writePolicyFile() throws Exception {
+    policyFile.write(policyFilePath);
+    FileSystem clusterFs = dfsCluster.getFileSystem();
+    clusterFs.copyFromLocalFile(false,
+        new Path(policyFilePath.getPath()),
+        new Path(policyFilePath.getPath()));
+  }
+
+  public static void setSystemProperties() throws Exception {
+    System.setProperty("solr.xml.persist", "true");
+    // Disable the block cache because we can run out of memory
+    // on a MiniCluster.
+    System.setProperty("solr.hdfs.blockcache.enabled", "false");
+    System.setProperty("solr.hdfs.home", dfsCluster.getURI().toString() + "/solr");
+    System.setProperty("solr.authorization.sentry.site", sentrySitePath.toURI().toURL().toString().substring("file:".length()));
+  }
+
+  public static void unsetSystemProperties() {
+    System.clearProperty("solr.xml.persist");
+    System.clearProperty("solr.hdfs.blockcache.enabled");
+    System.clearProperty("solr.hdfs.home");
+    System.clearProperty("solr.authorization.sentry.site");
+  }
+
+  public static void setGroupsAndRoles() throws Exception {
+    /**set local group mapping
+     * user0->group0->role0
+     * user1->group1->role1
+     * user2->group2->role2
+     * user3->group3->role3
+     */
+    String[] users = {"user0","user1","user2","user3"};
+    String[] groups = {"group0","group1","group2","group3"};
+    String[] roles = {"role0","role1","role2","role3"};
+
+    for (int i = 0; i < users.length; i++) {
+      addGroupsToUser(users[i], groups[i]);
+    }
+    addGroupsToUser(ADMIN_USER, ADMIN_GROUP);
+    writePolicyFile();
+
+    for (int i = 0; i < roles.length; i++) {
+      client.createRole(ADMIN_USER, roles[i]);
+      client.addRoleToGroups(ADMIN_USER, roles[i], Sets.newHashSet(groups[i]));
+    }
+
+    /**
+     * user[admin]->group[admin]->role[admin]
+     * grant ALL privilege on collection ALL to role admin
+     */
+    client.createRole(ADMIN_USER, ADMIN_ROLE);
+    client.addRoleToGroups(ADMIN_USER, ADMIN_ROLE, Sets.newHashSet(ADMIN_GROUP));
+    client.grantCollectionPrivilege(SearchConstants.ALL, ADMIN_USER, ADMIN_ROLE, SearchConstants.ALL);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrAdminOperations.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrAdminOperations.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrAdminOperations.java
new file mode 100644
index 0000000..00a7a89
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrAdminOperations.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sentry.tests.e2e.solr.db.integration;
+
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.solr.common.params.CollectionParams.CollectionAction;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertTrue;
+
+public class TestSolrAdminOperations extends AbstractSolrSentryTestWithDbProvider {
+  private static final Logger LOG = LoggerFactory.getLogger(TestSolrAdminOperations.class);
+  private static final String TEST_COLLECTION_NAME1 = "collection1";
+  private static final String COLLECTION_CONFIG_DIR = RESOURCES_DIR + File.separator + "collection1" + File.separator + "conf";
+
+  @Test
+  public void testAdminOperations() throws Exception {
+    /**
+     * Upload configs to ZK for create collection
+     */
+    uploadConfigDirToZk(COLLECTION_CONFIG_DIR);
+
+    /**
+     * verify admin user has all privileges
+     */
+    verifyCollectionAdminOpPass(ADMIN_USER, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(ADMIN_USER, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    String grantor = "user0";
+    /**
+     * user0->group0->role0
+     * grant ALL privilege on collection admin and collection1 to role0
+     */
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role0", SearchConstants.ALL);
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.ALL);
+
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    //revoke UPDATE privilege on collection collection1 from role1, create collection1 will be failed
+    client.revokeCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.UPDATE);
+
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    /**
+     * user1->group1->role1
+     * grant UPDATE privilege on collection admin and collection1 to role1
+     */
+    grantor = "user1";
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role1", SearchConstants.UPDATE);
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.UPDATE);
+
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    //revoke UPDATE privilege on collection admin from role1, create collection1 will be failed
+    client.revokeCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role1", SearchConstants.UPDATE);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+
+    /**
+     * user2->group2->role2
+     * grant QUERY privilege on collection admin and collection1 to role2
+     */
+    grantor = "user2";
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role2", SearchConstants.QUERY);
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.QUERY);
+
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    //grant UPDATE privilege on collection collection1 to role2, create collection1 will be failed
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.UPDATE);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+
+    //grant UPDATE privilege on collection admin to role2, create collection1 will be successful.
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role2", SearchConstants.UPDATE);
+
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    grantor = "user3";
+
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpFail(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+
+    /**
+     * user3->group3->role3
+     * grant UPDATE privilege on collection admin to role3
+     * grant QUERY privilege on collection collection1 to role3
+     */
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role3", SearchConstants.ALL);
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role3", SearchConstants.ALL);
+
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATE, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.RELOAD, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.CREATEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETEALIAS, TEST_COLLECTION_NAME1);
+    verifyCollectionAdminOpPass(grantor, CollectionAction.DELETE, TEST_COLLECTION_NAME1);
+  }
+
+  /**
+   * Test when the collection has been deleted, the privileges in the sentry service also should be deleted
+   * @throws Exception
+   */
+  @Test
+  public void testSyncPrivilegesWithDeleteCollection() throws Exception {
+    /**
+     * Upload configs to ZK for create collection
+     */
+    uploadConfigDirToZk(COLLECTION_CONFIG_DIR);
+    /**
+     * user0->group0->role0
+     * Grant ALL privilege on collection collection1 to role0
+     * Grant ALL privilege on collection admin to role0
+     * user0 can execute create & delete collection1 operation
+     */
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.ALL);
+    client.grantCollectionPrivilege(ADMIN_COLLECTION_NAME, ADMIN_USER, "role0", SearchConstants.ALL);
+
+    assertTrue("user0 has one privilege on collection admin",
+        client.listPrivilegesByRoleName("user0", "role0", Arrays.asList(new Collection(ADMIN_COLLECTION_NAME))).size() == 1);
+
+    assertTrue("user0 has one privilege on collection collection1",
+        client.listPrivilegesByRoleName("user0", "role0", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 1);
+
+    /**
+     * user1->group1->role1
+     * grant QUERY privilege on collection collection1 to role1
+     */
+
+    client.listPrivilegesByRoleName("user0", "role0", null);
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.ALL);
+    assertTrue("user1 has one privilege record",
+        client.listPrivilegesByRoleName("user1", "role1", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 1);
+
+    /**
+     * create collection collection1
+     */
+    setupCollection(TEST_COLLECTION_NAME1);
+    /**
+     * delete the collection1
+     */
+    deleteCollection(TEST_COLLECTION_NAME1);
+
+    //check the user0
+    assertTrue("user0 has one privilege on collection admin",
+        client.listPrivilegesByRoleName("user0", "role0", Arrays.asList(new Collection(ADMIN_COLLECTION_NAME))).size() == 1);
+
+    assertTrue("user0 has no privilege on collection collection1",
+        client.listPrivilegesByRoleName("user0", "role0", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 0);
+
+    //check the user1
+    assertTrue("user1 has no privilege on collection collection1",
+        client.listPrivilegesByRoleName("user1", "role1", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 0);
+
+
+    /**
+     * user2->group2->role2
+     * Grant UPDATE privilege on collection collection1 to role2
+     */
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.UPDATE);
+
+    assertTrue("user2 has one privilege on collection collection1",
+        client.listPrivilegesByRoleName("user2", "role2", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 1);
+
+    /**
+     * user3->group3->role3
+     * grant QUERY privilege on collection collection1 to role3
+     */
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role3", SearchConstants.QUERY);
+    assertTrue("user1 has one privilege record",
+        client.listPrivilegesByRoleName("user3", "role3", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 1);
+
+    /**
+     * create collection collection1
+     */
+    setupCollection(TEST_COLLECTION_NAME1);
+    /**
+     * delete the collection1
+     */
+    deleteCollection(TEST_COLLECTION_NAME1);
+
+    //check the user2
+    assertTrue("user2 has no privilege on collection collection1",
+        client.listPrivilegesByRoleName("user2", "role2", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 0);
+
+    //check the user3
+    assertTrue("user3 has no privilege on collection collection1",
+        client.listPrivilegesByRoleName("user3", "role3", Arrays.asList(new Collection(TEST_COLLECTION_NAME1))).size() == 0);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrDocLevelOperations.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrDocLevelOperations.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrDocLevelOperations.java
new file mode 100644
index 0000000..193743b
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrDocLevelOperations.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sentry.tests.e2e.solr.db.integration;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.impl.CloudSolrServer;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.Test;
+
+public class TestSolrDocLevelOperations extends AbstractSolrSentryTestWithDbProvider {
+  private static final String TEST_COLLECTION_NAME1 = "collection1";
+  private static final String AUTH_FIELD = "sentry_auth";
+  private static final int NUM_DOCS = 100;
+
+  private void setupCollectionWithDocSecurity(String name) throws Exception {
+    String configDir = RESOURCES_DIR + File.separator + "collection1"
+        + File.separator + "conf";
+    uploadConfigDirToZk(configDir);
+    // replace solrconfig.xml with solrconfig-doc-level.xml
+    uploadConfigFileToZk(configDir + File.separator + "solrconfig-doclevel.xml",
+        "solrconfig.xml");
+    setupCollection(name);
+  }
+
+  @Test
+  public void testDocLevelOperations() throws Exception {
+    setupCollectionWithDocSecurity(TEST_COLLECTION_NAME1);
+
+    createDocument(TEST_COLLECTION_NAME1);
+
+    CloudSolrServer server = getCloudSolrServer(TEST_COLLECTION_NAME1);
+    try {
+      // queries
+      SolrQuery query = new SolrQuery();
+      query.setQuery("*:*");
+
+      // as admin
+      setAuthenticationUser(ADMIN_USER);
+      QueryResponse  rsp = server.query(query);
+      SolrDocumentList docList = rsp.getResults();
+      assertEquals(NUM_DOCS, docList.getNumFound());
+
+      // as user0
+      setAuthenticationUser("user0");
+      client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.QUERY);
+      rsp = server.query(query);
+      docList = rsp.getResults();
+      assertEquals(NUM_DOCS/4, rsp.getResults().getNumFound());
+
+      //as user1
+      setAuthenticationUser("user1");
+      client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.QUERY);
+      rsp = server.query(query);
+      docList = rsp.getResults();
+      assertEquals(NUM_DOCS/4, rsp.getResults().getNumFound());  docList = rsp.getResults();
+      assertEquals(NUM_DOCS/4, rsp.getResults().getNumFound());
+
+      //as user2
+      setAuthenticationUser("user2");
+      client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.QUERY);
+      rsp = server.query(query);
+      docList = rsp.getResults();
+      assertEquals(NUM_DOCS/4, rsp.getResults().getNumFound());
+
+      //as user3
+      setAuthenticationUser("user3");
+      client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role3", SearchConstants.QUERY);
+      rsp = server.query(query);
+      docList = rsp.getResults();
+      assertEquals(NUM_DOCS/4, rsp.getResults().getNumFound());
+    } finally {
+      server.shutdown();
+    }
+
+    deleteCollection(TEST_COLLECTION_NAME1);
+  }
+
+  @Test
+  public void updateDocsTest() throws Exception {
+    setupCollectionWithDocSecurity(TEST_COLLECTION_NAME1);
+
+    createDocument(TEST_COLLECTION_NAME1);
+
+    CloudSolrServer server = getCloudSolrServer(TEST_COLLECTION_NAME1);
+    try {
+      setAuthenticationUser("user0");
+      client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.QUERY);
+      String docIdStr = Long.toString(1);
+
+      // verify we can't view one of the odd documents
+      SolrQuery query = new SolrQuery();
+      query.setQuery("id:"+docIdStr);
+      QueryResponse rsp = server.query(query);
+      assertEquals(0, rsp.getResults().getNumFound());
+
+      // overwrite the document that we can't see
+      setAuthenticationUser(ADMIN_USER);
+      ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
+      SolrInputDocument doc = new SolrInputDocument();
+      doc.addField("id", docIdStr);
+      doc.addField("description", "description" + docIdStr);
+      doc.addField(AUTH_FIELD, "role0");
+      docs.add(doc);
+      server.add(docs);
+      server.commit();
+
+      // verify we can now view the document
+      setAuthenticationUser("user0");
+      rsp = server.query(query);
+      assertEquals(1, rsp.getResults().getNumFound());
+    } finally {
+      server.shutdown();
+    }
+
+    deleteCollection(TEST_COLLECTION_NAME1);
+  }
+
+  /**
+   * Test to validate doc level security on collections without perm for Index level auth.
+   * @throws Exception
+   */
+  @Test
+  public void indexDocAuthTests() throws Exception {
+    setupCollectionWithDocSecurity(TEST_COLLECTION_NAME1);
+    try {
+      createDocument(TEST_COLLECTION_NAME1);
+      // test query for "*:*" fails as user0 (user0 doesn't have index level permissions but has doc level permissions set)
+      verifyQueryFail("user0", TEST_COLLECTION_NAME1, ALL_DOCS);
+      verifyQueryFail("user1", TEST_COLLECTION_NAME1, ALL_DOCS);
+      verifyQueryFail("user2", TEST_COLLECTION_NAME1, ALL_DOCS);
+      verifyQueryFail("user3", TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    } finally {
+      deleteCollection(TEST_COLLECTION_NAME1);
+    }
+  }
+
+  /**
+   * Creates docs as follows and verifies queries work as expected:
+   * - creates NUM_DOCS documents, where the document id equals the order
+   *   it was created in, starting at 0
+   * - when id % 4 == 0, documents get "role0" auth token
+   * - when id % 4 == 1, documents get "role1" auth token
+   * - when id % 4 == 2, documents get "role2" auth token
+   * - when id % 4 == 3, documents get "role3" auth token
+   * - all documents get a admin role
+   */
+  private void createDocument(String collectionName) throws Exception {
+    // ensure no current documents
+    verifyDeletedocsPass(ADMIN_USER, collectionName, true);
+
+    // create documents
+    ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
+    for (int i = 0; i < NUM_DOCS; ++i) {
+      SolrInputDocument doc = new SolrInputDocument();
+      String iStr = Long.toString(i);
+      doc.addField("id", iStr);
+      doc.addField("description", "description" + iStr);
+
+      if (i % 4 == 0) {
+        doc.addField(AUTH_FIELD, "role0");
+      } else if (i % 4 ==1) {
+        doc.addField(AUTH_FIELD, "role1");
+      } else if (i % 4 ==2) {
+        doc.addField(AUTH_FIELD, "role2");
+      } else {
+        doc.addField(AUTH_FIELD, "role3");
+      }
+      doc.addField(AUTH_FIELD, ADMIN_ROLE);
+      docs.add(doc);
+    }
+
+    setAuthenticationUser(ADMIN_USER);
+    CloudSolrServer server = getCloudSolrServer(collectionName);
+    try {
+      server.add(docs);
+      server.commit(true, true);
+    } finally {
+      server.shutdown();
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrQueryOperations.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrQueryOperations.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrQueryOperations.java
new file mode 100644
index 0000000..afe6912
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrQueryOperations.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sentry.tests.e2e.solr.db.integration;
+
+import java.io.File;
+
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+public class TestSolrQueryOperations extends AbstractSolrSentryTestWithDbProvider {
+  private static final Logger LOG = LoggerFactory.getLogger(TestSolrQueryOperations.class);
+  private static final String TEST_COLLECTION_NAME1 = "collection1";
+  private static final String COLLECTION_CONFIG_DIR = RESOURCES_DIR + File.separator + "collection1" + File.separator + "conf";
+
+  @Test
+  public void testQueryOperations() throws Exception {
+    /**
+     * Upload configs to ZK for create collection
+     */
+    uploadConfigDirToZk(COLLECTION_CONFIG_DIR);
+    /**
+     * create collection collection1 as admin user
+     * and clean all document in the collection1
+     */
+    setupCollection(TEST_COLLECTION_NAME1);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    /**
+     * add a new document into collection1 for testing
+     */
+    SolrInputDocument solrInputDoc = createSolrTestDoc();
+    uploadSolrDoc(TEST_COLLECTION_NAME1, solrInputDoc);
+
+    /**
+     * user0->group0->role0
+     * grant ALL privilege on collection collection1 to role0
+     */
+    String grantor = "user0";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.ALL);
+    verifyQueryPass(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    client.revokeCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.UPDATE);
+    verifyQueryPass(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    client.revokeCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.QUERY);
+    verifyQueryFail(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    /**
+     * user1->group1->role1
+     * grant QUERY privilege on collection collection1 to role1
+     */
+    grantor = "user1";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.QUERY);
+    verifyQueryPass(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    client.revokeCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.QUERY);
+    verifyQueryFail(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    /**
+     * user2->group2->role2
+     * grant UPDATE privilege on collection collection1 to role2
+     */
+    grantor = "user2";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.UPDATE);
+    verifyQueryFail(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.QUERY);
+    verifyQueryPass(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    client.renameCollectionPrivilege(TEST_COLLECTION_NAME1, "new_" + TEST_COLLECTION_NAME1, ADMIN_USER);
+    verifyQueryFail(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    grantor = "user3";
+    verifyQueryFail(grantor, TEST_COLLECTION_NAME1, ALL_DOCS);
+
+    deleteCollection(TEST_COLLECTION_NAME1);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/3893e22d/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrUpdateOperations.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrUpdateOperations.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrUpdateOperations.java
new file mode 100644
index 0000000..de18979
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/db/integration/TestSolrUpdateOperations.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sentry.tests.e2e.solr.db.integration;
+
+import java.io.File;
+
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+public class TestSolrUpdateOperations extends AbstractSolrSentryTestWithDbProvider {
+  private static final Logger LOG = LoggerFactory.getLogger(TestSolrUpdateOperations.class);
+  private static final String TEST_COLLECTION_NAME1 = "collection1";
+  private static final String COLLECTION_CONFIG_DIR = RESOURCES_DIR + File.separator + "collection1" + File.separator + "conf";
+
+  @Test
+  public void testUpdateOperations() throws Exception {
+    /**
+     * Upload configs to ZK for create collection
+     */
+    uploadConfigDirToZk(COLLECTION_CONFIG_DIR);
+    /**
+     * create collection collection1 as admin user
+     * and clean all document in the collection1
+     */
+    setupCollection(TEST_COLLECTION_NAME1);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+
+    SolrInputDocument solrInputDoc = createSolrTestDoc();
+
+    /**
+     * user0->group0->role0
+     * grant ALL privilege on collection collection1 to role0
+     */
+    String grantor = "user0";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role0", SearchConstants.ALL);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    verifyUpdatePass(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsPass(grantor, TEST_COLLECTION_NAME1, false);
+
+    //drop privilege
+    client.dropCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER);
+    verifyUpdateFail(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    uploadSolrDoc(TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsFail(grantor, TEST_COLLECTION_NAME1, false);
+
+    /**
+     * user1->group1->role1
+     * grant UPDATE privilege on collection collection1 to role1
+     */
+    grantor = "user1";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.UPDATE);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    verifyUpdatePass(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsPass(grantor, TEST_COLLECTION_NAME1, false);
+
+    //revoke privilege
+    client.revokeCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role1", SearchConstants.ALL);
+    verifyUpdateFail(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    uploadSolrDoc(TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsFail(grantor, TEST_COLLECTION_NAME1, false);
+
+    /**
+     * user2->group2->role2
+     * grant QUERY privilege on collection collection1 to role2
+     */
+    grantor = "user2";
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.QUERY);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    verifyUpdateFail(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    uploadSolrDoc(TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsFail(grantor, TEST_COLLECTION_NAME1, false);
+
+    client.grantCollectionPrivilege(TEST_COLLECTION_NAME1, ADMIN_USER, "role2", SearchConstants.ALL);
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    verifyUpdatePass(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsPass(grantor, TEST_COLLECTION_NAME1, false);
+
+    grantor = "user3";
+    cleanSolrCollection(TEST_COLLECTION_NAME1);
+    verifyUpdateFail(grantor, TEST_COLLECTION_NAME1, solrInputDoc);
+    uploadSolrDoc(TEST_COLLECTION_NAME1, solrInputDoc);
+    verifyDeletedocsFail(grantor, TEST_COLLECTION_NAME1, false);
+
+    deleteCollection(TEST_COLLECTION_NAME1);
+  }
+}
\ No newline at end of file