You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by gc...@apache.org on 2013/12/26 20:20:06 UTC

git commit: SENTRY-71: Solr Update authorization tests for Sentry (Vamsee Yarlagadda via Gregory Chanan)

Updated Branches:
  refs/heads/master b9aa0b7a0 -> 5601cdd18


SENTRY-71: Solr Update authorization tests for Sentry (Vamsee Yarlagadda via  Gregory Chanan)


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

Branch: refs/heads/master
Commit: 5601cdd18c4a89b468c1c0cdde3b68fbabf28ceb
Parents: b9aa0b7
Author: Gregory Chanan <gc...@cloudera.com>
Authored: Mon Dec 23 15:44:01 2013 -0800
Committer: Gregory Chanan <gc...@cloudera.com>
Committed: Mon Dec 23 15:44:01 2013 -0800

----------------------------------------------------------------------
 sentry-tests/sentry-tests-solr/pom.xml          |  15 +-
 .../e2e/solr/AbstractSolrSentryTestBase.java    | 335 ++++++++++++++++++-
 .../e2e/solr/JunitAuthenticationFilter.java     |  55 ---
 .../ModifiableUserAuthenticationFilter.java     |  68 ++++
 .../e2e/solr/TestSimpleUpdatePositiveTest.java  |  44 ---
 .../tests/e2e/solr/TestUpdateOperations.java    |  79 +++++
 .../solr/sentry/test-authz-provider.ini         |  35 +-
 7 files changed, 521 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/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 23a2ec5..3f0fa2d 100644
--- a/sentry-tests/sentry-tests-solr/pom.xml
+++ b/sentry-tests/sentry-tests-solr/pom.xml
@@ -18,14 +18,22 @@ limitations under the License.
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
     <groupId>org.apache.sentry</groupId>
     <artifactId>sentry-tests</artifactId>
     <version>1.3.0-incubating-SNAPSHOT</version>
   </parent>
+
   <artifactId>sentry-tests-solr</artifactId>
   <name>Sentry Solr Tests</name>
   <description>end to end tests for sentry-solr integration</description>
+
+  <properties>
+    <lucene-junit.version>4.10</lucene-junit.version>
+    <carrot-search.version>2.0.10</carrot-search.version>
+  </properties>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.solr</groupId>
@@ -46,7 +54,12 @@ limitations under the License.
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
-      <version>4.10</version> <!-- required for LuceneTestCase -->
+      <version>${lucene-junit.version}</version> <!-- required for LuceneTestCase -->
+    </dependency>
+    <dependency>
+      <groupId>com.carrotsearch.randomizedtesting</groupId>
+      <artifactId>randomizedtesting-runner</artifactId>
+      <version>${carrot-search.version}</version>
     </dependency>
   </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/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 52fcecf..c0abd28 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
@@ -18,7 +18,11 @@ package org.apache.sentry.tests.e2e.solr;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
+import java.util.Random;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -27,11 +31,17 @@ import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hdfs.MiniDFSCluster;
 import org.apache.solr.SolrTestCaseJ4;
+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.cloud.AbstractFullDistribZkTestBase;
 import org.apache.solr.cloud.ZkController;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.servlet.SolrDispatchFilter;
 
+import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -41,8 +51,11 @@ import org.slf4j.LoggerFactory;
 
 public abstract class AbstractSolrSentryTestBase extends AbstractFullDistribZkTestBase {
   private static final Logger LOG = LoggerFactory.getLogger(AbstractSolrSentryTestBase.class);
+  protected static final String SENTRY_ERROR_MSG = "401, message:Unauthorized";
   private static MiniDFSCluster dfsCluster;
   private static SortedMap<Class, String> extraRequestFilters;
+  protected static final String ADMIN_USER = "admin";
+  protected static final Random RANDOM = new Random();
 
   private static void addPropertyToSentry(StringBuilder builder, String name, String value) {
     builder.append("<property>\n");
@@ -92,7 +105,7 @@ public abstract class AbstractSolrSentryTestBase extends AbstractFullDistribZkTe
         return true;
       }
     });
-    extraRequestFilters.put(JunitAuthenticationFilter.class, "*");
+    extraRequestFilters.put(ModifiableUserAuthenticationFilter.class, "*");
   }
 
   @AfterClass
@@ -104,17 +117,23 @@ public abstract class AbstractSolrSentryTestBase extends AbstractFullDistribZkTe
     extraRequestFilters = null;
   }
 
-  @Override
-  protected String getDataDir(String dataDir) throws IOException {
-    return HdfsTestUtil.getDataDir(dfsCluster, dataDir);
-  }
-
   @Before
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
+  public void setupBeforeTest() throws Exception {
     System.setProperty("numShards", Integer.toString(sliceCount));
     System.setProperty("solr.xml.persist", "true");
+    super.setUp();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    super.tearDown();
+    System.clearProperty("numShards");
+    System.clearProperty("solr.xml.persist");
+  }
+
+  @Override
+  protected String getDataDir(String dataDir) throws IOException {
+    return HdfsTestUtil.getDataDir(dfsCluster, dataDir);
   }
 
   @Override
@@ -133,6 +152,304 @@ public abstract class AbstractSolrSentryTestBase extends AbstractFullDistribZkTe
   }
 
   /**
+   * Set the proper user in the Solr authentication filter
+   * @param solrUser
+   */
+  protected void setAuthenticationUser(String solrUser) throws Exception {
+    ModifiableUserAuthenticationFilter.setUser(solrUser);
+  }
+
+  /**
+   * Function to return the user name based on the permissions provided.
+   * @param collectionName - Name of the solr collection.
+   * @param isQuery - Boolean that specifies query permission.
+   * @param isUpdate - Boolean that specifies update permission.
+   * @param isAll - Boolean that specifies all permission.
+   * @return - String which represents the Solr username.
+   */
+  protected String getUsernameForPermissions(String collectionName,
+                                             boolean isQuery,
+                                             boolean isUpdate,
+                                             boolean isAll) {
+    StringBuilder finalStr = new StringBuilder();
+    finalStr.append(collectionName);
+    finalStr.append("_");
+    StringBuilder permissions = new StringBuilder();
+    if (isQuery) {
+      permissions.append("q");
+    }
+
+    if (isUpdate) {
+      permissions.append("u");
+    }
+
+    if (isAll) {
+      permissions.append("a");
+    }
+
+    finalStr.append(permissions.toString());
+    return finalStr.toString();
+  }
+
+  /**
+   * Method to validate Solr update passes
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to which the data has to be updated
+   * @param solrInputDoc - Instance of SolrInputDocument
+   * @throws Exception
+   */
+  protected void verifyUpdatePass(String solrUserName,
+                                   String collectionName,
+                                   SolrInputDocument solrInputDoc)
+                                   throws Exception {
+    int originalSolrDocCount = getSolrDocs(collectionName).size();
+    setAuthenticationUser(solrUserName);
+    CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+    try {
+      cloudSolrServer.add(solrInputDoc);
+      cloudSolrServer.commit();
+    } finally {
+      cloudSolrServer.shutdown();
+    }
+
+    // Validate Solr content to check whether the update command went through.
+    // Authenticate as user "admin"
+    validateSolrDocCountAndContent(collectionName, originalSolrDocCount+1, solrInputDoc);
+  }
+
+  /**
+   * Method to validate Solr update fails
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to which the data has to be updated
+   * @param solrInputDoc - Instance of SolrInputDocument
+   * @throws Exception
+   */
+  protected void verifyUpdateFail(String solrUserName,
+                                   String collectionName,
+                                   SolrInputDocument solrInputDoc)
+                                   throws Exception {
+    int originalSolrDocCount = getSolrDocs(collectionName).size();
+    setAuthenticationUser(solrUserName);
+    CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+    try {
+      cloudSolrServer.add(solrInputDoc);
+      cloudSolrServer.commit();
+      fail("The specified user: " + solrUserName + " shouldn't get update access!");
+    } catch (Exception exception) {
+      assertTrue("Expected " + SENTRY_ERROR_MSG + " in " + exception.toString(),
+          exception.toString().contains(SENTRY_ERROR_MSG));
+    } finally {
+      cloudSolrServer.shutdown();
+    }
+
+    // Validate Solr content to check whether the update command didn't go through.
+    // Authenticate as user "admin"
+    validateSolrDocCountAndContent(collectionName, originalSolrDocCount, null);
+  }
+
+  /**
+   * Method to validate Solr deletedocs passes
+   * (This function doesn't check if there is at least one Solr document present in Solr)
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to which the data has to be updated
+   * @param allowZeroDocs - Boolean for running this method only if there is atleast one Solr doc present.
+   * @throws MalformedURLException, SolrServerException, IOException
+   */
+  protected void verifyDeletedocsPass(String solrUserName,
+                                   String collectionName, boolean allowZeroDocs)
+                                   throws Exception {
+    int originalSolrDocCount = getSolrDocs(collectionName).size();
+    if (allowZeroDocs == false) {
+      assertTrue("Solr should contain atleast one solr doc to run this test.", originalSolrDocCount > 0);
+    }
+
+    setAuthenticationUser(solrUserName);
+    CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+    try {
+      cloudSolrServer.deleteByQuery("*:*");
+      cloudSolrServer.commit();
+    } finally {
+      cloudSolrServer.shutdown();
+    }
+
+    // Validate Solr content to check whether the update command didn't go through.
+    // Authenticate as user "admin"
+    validateSolrDocCountAndContent(collectionName, 0, null);
+  }
+
+  /**
+   * Method to validate Solr deletedocs fails
+   * (This function doesn't check if there is at least one Solr document present in Solr)
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to which the data has to be updated
+   * @param allowZeroDocs - Boolean for running this method only if there is atleast one Solr doc present.
+   * @throws Exception
+   */
+  protected void verifyDeletedocsFail(String solrUserName,
+                                   String collectionName, boolean allowZeroDocs)
+                                   throws Exception {
+    int originalSolrDocCount = getSolrDocs(collectionName).size();
+    if (allowZeroDocs == false) {
+      assertTrue("Solr should contain atleast one solr doc to run this test.", originalSolrDocCount > 0);
+    }
+
+    setAuthenticationUser(solrUserName);
+    CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+    try {
+      cloudSolrServer.deleteByQuery("*:*");
+      cloudSolrServer.commit();
+      fail("The specified user: " + solrUserName + " shouldn't get deletedocs access!");
+    } catch (Exception exception) {
+      assertTrue("Expected " + SENTRY_ERROR_MSG + " in " + exception.toString(),
+          exception.toString().contains(SENTRY_ERROR_MSG));
+    } finally {
+      cloudSolrServer.shutdown();
+    }
+
+    // Validate Solr content to check whether the deletedocs command didn't go through.
+    // Authenticate as user "admin"
+    validateSolrDocCountAndContent(collectionName, originalSolrDocCount, null);
+  }
+
+  /**
+   * Function to verify whether Solr doc count matches the expected number and
+   * also to verify if the Input document is present in present in the response.
+   * @param collectionName - Name of the Solr collection
+   * @param expectedDocCount - Count of expected Solr docs
+   * @param solrInputDoc - Solr doc inserted into Solr
+   * @throws Exception
+   */
+  public void validateSolrDocCountAndContent(String collectionName, int expectedDocCount, SolrInputDocument solrInputDoc)
+                                   throws Exception {
+    // Authenticate as user "admin"
+    setAuthenticationUser(ADMIN_USER);
+    SolrDocumentList solrRespDocs = getSolrDocs(collectionName);
+    assertEquals("Expected: " + expectedDocCount + " Solr docs; But, found "
+        + solrRespDocs.size() + " Solr docs.", solrRespDocs.size(), expectedDocCount);
+      if (solrInputDoc != null) {
+        validateSolrDocContent(solrInputDoc, solrRespDocs);
+      }
+  }
+
+  /**
+   * Function to query the collection and fetch the Solr docs
+   * @param collectionName -  Name of the collection
+   * @return -  Instance of SolrDocumentList
+   * @throws Exception
+   */
+  protected SolrDocumentList getSolrDocs(String collectionName) throws Exception {
+    // Authenticate as user "admin"
+    setAuthenticationUser(ADMIN_USER);
+    CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+    SolrDocumentList solrDocs = null;
+    try {
+      SolrQuery query = new SolrQuery("*:*");
+      QueryResponse response = cloudSolrServer.query(query);
+      solrDocs = response.getResults();
+    } finally {
+      cloudSolrServer.shutdown();
+    }
+
+    return solrDocs;
+  }
+
+  /**
+   * Function to validate the content of Solr response with that of input document.
+   * @param solrInputDoc - Solr doc inserted into Solr
+   * @param solrRespDocs - List of Solr doc obtained as response
+   * (NOTE: This function ignores "_version_" field in validating Solr doc content)
+   */
+  public void validateSolrDocContent(SolrInputDocument solrInputDoc, SolrDocumentList solrRespDocs) {
+    solrInputDoc.removeField("_version_");
+    for (SolrDocument solrRespDoc : solrRespDocs) {
+      solrRespDoc.removeFields("_version_");
+      String expFieldValue = (String) solrInputDoc.getFieldValue("id");
+      String resFieldValue = (String) solrRespDoc.getFieldValue("id");
+      if (expFieldValue.equals(resFieldValue)) {
+        assertEquals("Expected " + solrInputDoc.size() + " fields. But, found "
+            + solrRespDoc.size() + " fields", solrInputDoc.size() , solrRespDoc.size());
+        for (String field : solrInputDoc.getFieldNames()) {
+          expFieldValue = (String) solrInputDoc.getFieldValue(field);
+          resFieldValue = (String) solrRespDoc.getFieldValue(field);
+          assertEquals("Expected value for field: " + field + " is " + expFieldValue
+              + "; But, found " + resFieldValue, expFieldValue, resFieldValue);
+        }
+
+        return;
+      }
+    }
+
+    fail("Solr doc not found in Solr collection");
+  }
+
+  /**
+   * Function to return the instance of CloudSolrServer for the collectionName specified
+   * @param collectionName - Name of the collection
+   * @return instance of CloudSolrServer
+   * @throws MalformedURLException
+   */
+  protected CloudSolrServer getCloudSolrServer(String collectionName) throws MalformedURLException {
+    CloudSolrServer cloudSolrServer = new CloudSolrServer(zkServer.getZkAddress(),
+        random().nextBoolean());
+    cloudSolrServer.setDefaultCollection(collectionName);
+    cloudSolrServer.connect();
+    return cloudSolrServer;
+  }
+
+  /**
+   * Function to create a solr collection with the name passed as parameter
+   * (Runs commands as ADMIN user)
+   * @param collectionName - Name of the collection
+   * @throws Exception
+   */
+  protected void setupCollection(String collectionName) throws Exception {
+    // Authenticate as user "admin"
+    setAuthenticationUser(ADMIN_USER);
+    uploadConfigDirToZk(getSolrHome() + File.separator + DEFAULT_COLLECTION
+      + File.separator + "conf");
+    createCollection(collectionName, 1, 1, 1);
+    waitForRecoveriesToFinish(collectionName, false);
+  }
+
+  /**
+   * Function to clean Solr collections
+   * @param collectionName - Name of the collection
+   * @throws Exception
+   */
+  protected void cleanSolrCollection(String collectionName)
+                                     throws Exception {
+    verifyDeletedocsPass(ADMIN_USER, collectionName, true);
+  }
+
+  /**
+   * Function to create a test Solrdoc with a random number as the ID
+   * @throws Exception
+   */
+  protected SolrInputDocument createSolrTestDoc() throws Exception {
+    SolrInputDocument solrInputDoc = new SolrInputDocument();
+    String solrDocId = String.valueOf(RANDOM.nextInt());
+    solrInputDoc.addField("id", solrDocId);
+    solrInputDoc.addField("name", "testdoc" + solrDocId);
+    return solrInputDoc;
+  }
+
+  /**
+   * Load Solr collection with the SolrDocument passed.
+   * @param collectionName - Name of the Solr collection
+   * @param solrInputDoc - Solr document to be uploaded
+   * (If solrInputDoc is null, then a test Solr doc will be uploaded)
+   * @throws Exception
+   */
+  protected void uploadSolrDoc(String collectionName,
+                                       SolrInputDocument solrInputDoc) throws Exception {
+    if (solrInputDoc == null) {
+      solrInputDoc = createSolrTestDoc();
+    }
+
+    verifyUpdatePass(ADMIN_USER, collectionName, solrInputDoc);
+  }
+
+  /**
    * Subclasses can override this to change a test's solr home
    * (default is in test-files)
    */

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/JunitAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/JunitAuthenticationFilter.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/JunitAuthenticationFilter.java
deleted file mode 100644
index 7e2690f..0000000
--- a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/JunitAuthenticationFilter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sentry.tests.e2e.solr;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import org.apache.solr.servlet.SolrHadoopAuthenticationFilter;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Authentication Filter that authenticates any request as user "junit"
- */
-public class JunitAuthenticationFilter implements Filter {
-  private static final Logger LOG = LoggerFactory
-    .getLogger(JunitAuthenticationFilter.class);
-  private static final String userName = "junit";
-
-  @Override
-  public void init(FilterConfig filterConfig) throws ServletException {
-  }
-
-  @Override
-  public void destroy() {
-  }
-
-  @Override
-  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-    HttpServletRequest httpRequest = (HttpServletRequest) request;
-    httpRequest.setAttribute(SolrHadoopAuthenticationFilter.USER_NAME, userName);
-    chain.doFilter(request, response);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/ModifiableUserAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/ModifiableUserAuthenticationFilter.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/ModifiableUserAuthenticationFilter.java
new file mode 100644
index 0000000..9f550c4
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/ModifiableUserAuthenticationFilter.java
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.solr.servlet.SolrHadoopAuthenticationFilter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Authentication Filter that authenticates any request as user "junit"
+ */
+public class ModifiableUserAuthenticationFilter implements Filter {
+  private static final Logger LOG = LoggerFactory
+    .getLogger(ModifiableUserAuthenticationFilter.class);
+
+  /**
+   * String that saves the user to be authenticated into Solr
+   */
+  private static String userName = "admin";
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+  }
+
+  @Override
+  public void destroy() {
+  }
+
+  @Override
+  public void doFilter(ServletRequest request, ServletResponse response,
+                       FilterChain chain) throws IOException, ServletException {
+    HttpServletRequest httpRequest = (HttpServletRequest) request;
+    httpRequest.setAttribute(SolrHadoopAuthenticationFilter.USER_NAME, userName);
+    chain.doFilter(request, response);
+  }
+
+  /**
+   * Function to set the userName with the corresponding user passed as parameter
+   * @param solrUser
+   */
+  public static void setUser(String solrUser) {
+    userName = solrUser;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestSimpleUpdatePositiveTest.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestSimpleUpdatePositiveTest.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestSimpleUpdatePositiveTest.java
deleted file mode 100644
index c5174b6..0000000
--- a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestSimpleUpdatePositiveTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sentry.tests.e2e.solr;
-
-import java.io.File;
-import org.apache.solr.client.solrj.impl.CloudSolrServer;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
-
-@ThreadLeakScope(Scope.NONE) // hdfs client currently leaks thread(s)
-public class TestSimpleUpdatePositiveTest extends AbstractSolrSentryTestBase {
-  private static final Logger LOG = LoggerFactory.getLogger(TestSimpleUpdatePositiveTest.class);
-
-  /**
-   * Solr-sentry positive test on updates
-   */
-  @Override
-  public void doTest() throws Exception {
-    uploadConfigDirToZk(getSolrHome() + File.separator + DEFAULT_COLLECTION
-      + File.separator + "conf");
-    createCollection(DEFAULT_COLLECTION, 1, 1, 1);
-    waitForRecoveriesToFinish(DEFAULT_COLLECTION, false);
-    CloudSolrServer cloudServer = getCommonCloudSolrServer();
-    cloudServer.deleteByQuery("*:*");
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestUpdateOperations.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestUpdateOperations.java b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestUpdateOperations.java
new file mode 100644
index 0000000..131fa2c
--- /dev/null
+++ b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestUpdateOperations.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
+import java.util.ArrayList;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.solr.common.SolrInputDocument;
+
+@ThreadLeakScope(Scope.NONE) // hdfs client currently leaks thread(s)
+public class TestUpdateOperations extends AbstractSolrSentryTestBase {
+  private static final Logger LOG = LoggerFactory
+      .getLogger(TestUpdateOperations.class);
+  private static final String COLLECTION_NAME = "sentryCollection";
+  private static final List<Boolean> BOOLEAN_VALUES = Arrays.asList(new Boolean[]{true, false});
+
+  @Override
+  public void doTest() throws Exception {
+    setupCollection(COLLECTION_NAME);
+    ArrayList<String> testFailures = new ArrayList<String>();
+
+    for (boolean query : BOOLEAN_VALUES) {
+      for (boolean update : BOOLEAN_VALUES) {
+        for (boolean all : BOOLEAN_VALUES) {
+          // Create user name to be used for Solr requests based on the permissions generated by the for-loop.
+          String test_user = getUsernameForPermissions(COLLECTION_NAME, query, update, all);
+          LOG.info("TEST_USER: " + test_user);
+
+          try {
+            if (all || update) {
+              cleanSolrCollection(COLLECTION_NAME);
+              SolrInputDocument solrInputDoc = createSolrTestDoc();
+              verifyUpdatePass(test_user, COLLECTION_NAME, solrInputDoc);
+
+              cleanSolrCollection(COLLECTION_NAME);
+              uploadSolrDoc(COLLECTION_NAME, null);
+              verifyDeletedocsPass(test_user, COLLECTION_NAME, false);
+            } else {
+              cleanSolrCollection(COLLECTION_NAME);
+              SolrInputDocument solrInputDoc = createSolrTestDoc();
+              verifyUpdateFail(test_user, COLLECTION_NAME, solrInputDoc);
+
+              cleanSolrCollection(COLLECTION_NAME);
+              uploadSolrDoc(COLLECTION_NAME, null);
+              verifyDeletedocsFail(test_user, COLLECTION_NAME, false);
+            }
+          } catch (Throwable testException) {
+            testFailures.add("\n\nTestFailure: User -> " + test_user + "\n"
+                + testException.toString());
+          }
+        }
+      }
+    }
+
+    assertEquals("Total test failures: " + testFailures.size() + " \n\n"
+        + testFailures.toString(), 0, testFailures.size());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/5601cdd1/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini b/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
index 34926ae..f988eae 100644
--- a/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
+++ b/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
@@ -17,9 +17,42 @@
 
 [groups]
 junit = junit_role
+admin = admin_role
+sentry_collection_query_group = sentry_collection_query_role
+sentry_collection_update_group = sentry_collection_update_role
+sentry_collection_query_update_group = sentry_collection_query_update_role
+sentry_collection_all_group = sentry_collection_all_role
+admin_query_group = admin_query_role
+admin_update_group = admin_update_role
+admin_query_update_group = admin_query_update_role
+admin_all_group = admin_all_role
 
 [roles]
 junit_role = collection=admin, collection=collection1
+admin_role = collection=admin, collection=collection1, collection=sentryCollection
+sentry_collection_query_role = collection=sentryCollection->action=query
+sentry_collection_update_role = collection=sentryCollection->action=update
+sentry_collection_query_update_role = collection=sentryCollection->action=query, collection=sentryCollection->action=update
+sentry_collection_all_role = collection=sentryCollection->action=*
+admin_query_role = collection=admin->action=query
+admin_update_role = collection=admin->action=update
+admin_query_update_role = collection=admin->action=query, collection=admin->action=update
+admin_all_role = collection=admin->action=*
 
 [users]
-junit=junit
+junit = junit
+admin = admin
+sentryCollection_q = sentry_collection_query_group
+sentryCollection_u = sentry_collection_update_group
+sentryCollection_a = sentry_collection_all_group
+sentryCollection_qu = sentry_collection_query_update_group
+sentryCollection_ua = sentry_collection_update_group, sentry_collection_all_group
+sentryCollection_qa = sentry_collection_query_group, sentry_collection_all_group
+sentryCollection_qua = sentry_collection_query_group, sentry_collection_update_group, sentry_collection_all_group
+admin_q = admin_query_group
+admin_u = admin_update_group
+admin_a = admin_all_group
+admin_qu = admin_query_update_group
+admin_ua = admin_update_group, admin_all_group
+admin_qa = admin_query_group, admin_all_group
+admin_qua = admin_query_group, admin_update_group, admin_all_group
\ No newline at end of file