You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by br...@apache.org on 2014/02/21 19:22:48 UTC

[2/2] git commit: SENTRY-121: Merge master into db_policy_store

SENTRY-121: Merge master into db_policy_store


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

Branch: refs/heads/db_policy_store
Commit: 22b6a3480f11dabad8581e365d7f82217e731aee
Parents: 822f4bf
Author: Brock Noland <br...@apache.org>
Authored: Fri Feb 21 12:22:31 2014 -0600
Committer: Brock Noland <br...@apache.org>
Committed: Fri Feb 21 12:22:31 2014 -0600

----------------------------------------------------------------------
 pom.xml                                         |  20 +-
 .../binding/hive/HiveAuthzBindingHook.java      |  72 +--
 .../sentry/binding/hive/conf/HiveAuthzConf.java |   2 +-
 .../binding/solr/authz/SolrAuthzBinding.java    |  13 +
 .../binding/solr/TestSolrAuthzBinding.java      |  28 +
 .../src/test/resources/test-authz-provider.ini  |   2 +-
 sentry-core/sentry-core-common/pom.xml          |  12 +
 .../sentry/core/common/utils/PathUtils.java     | 131 +++++
 .../sentry/core/common/utils/TestPathUtils.java |  76 +++
 sentry-dist/pom.xml                             |   2 +-
 sentry-dist/src/main/assembly/src.xml           | 101 +---
 .../sentry/policy/db/DBWildcardPermission.java  |  40 +-
 .../policy/db/TestDBWildcardPermission.java     |   5 +-
 sentry-provider/sentry-provider-common/pom.xml  |   5 +
 .../provider/common/AuthorizationProvider.java  |   6 +
 .../common/NoAuthorizationProvider.java         |   5 +
 .../provider/common/NoGroupMappingService.java  |  33 ++
 .../common/TestNoAuthorizationProvider.java     |  39 ++
 .../src/main/resources/sentry-mysql-1.4.0.sql   |  16 +
 .../src/main/resources/sentry-oracle-1.4.0.sql  |  15 +
 .../main/resources/sentry-postgres-1.4.0.sql    |  15 +
 sentry-provider/sentry-provider-file/pom.xml    |   4 +
 .../file/ResourceAuthorizationProvider.java     |   5 +
 .../provider/file/TestGetGroupMapping.java      |  54 ++
 .../e2e/hive/TestPrivilegesAtDatabaseScope.java |   4 +
 .../e2e/hive/hiveserver/AbstractHiveServer.java |   2 +-
 sentry-tests/sentry-tests-solr/pom.xml          |  19 +-
 .../e2e/solr/AbstractSolrSentryTestBase.java    | 569 ++++++++++++++++++-
 .../e2e/solr/JunitAuthenticationFilter.java     |  55 --
 .../ModifiableUserAuthenticationFilter.java     |  79 +++
 .../e2e/solr/TestCollAdminCoreOperations.java   | 145 +++++
 .../tests/e2e/solr/TestQueryOperations.java     |  78 +++
 .../e2e/solr/TestSimpleUpdatePositiveTest.java  |  44 --
 .../tests/e2e/solr/TestUpdateOperations.java    |  87 +++
 .../solr/collection1/conf/solrconfig.xml        |   2 +-
 .../solr/sentry/test-authz-provider.ini         |  98 +++-
 36 files changed, 1609 insertions(+), 274 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 423623a..5807d86 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,7 @@ limitations under the License.
     <maven.eclipse.plugin.version>2.9</maven.eclipse.plugin.version>
     <maven.enforcer.plugin.version>1.3.1</maven.enforcer.plugin.version>
     <build.helper.maven.plugin.version>1.8</build.helper.maven.plugin.version>
+    <commons.lang.version>2.6</commons.lang.version>
     <datanucleus.maven.plugin.version>3.3.0-release</datanucleus.maven.plugin.version>
     <datanucleus-api-jdo.version>3.2.1</datanucleus-api-jdo.version>
     <datanucleus-core.version>3.2.2</datanucleus-core.version>
@@ -92,6 +93,11 @@ limitations under the License.
         <version>${commons-cli.version}</version>
       </dependency>
       <dependency>
+        <groupId>commons-lang</groupId>
+        <artifactId>commons-lang</artifactId>
+        <version>${commons.lang.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.apache.derby</groupId>
         <artifactId>derby</artifactId>
         <version>${derby.version}</version>
@@ -143,6 +149,12 @@ limitations under the License.
       </dependency>
       <dependency>
         <groupId>org.apache.solr</groupId>
+        <artifactId>solr-sentry-handlers</artifactId>
+        <version>${solr.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.solr</groupId>
         <artifactId>solr-solrj</artifactId>
         <version>${solr.version}</version>
       </dependency>
@@ -419,11 +431,11 @@ limitations under the License.
                   <exclude>**/nb-configuration.xml</exclude>
                   <exclude>**.patch</exclude>
                   <exclude>README*</exclude>
-                  <exclude>.project</exclude>
+                  <exclude>**/.project</exclude>
                   <exclude>**/target/</exclude>
-                  <exclude>.settings</exclude>
-                  <exclude>.metadata/</exclude>
-                  <exclude>.classpath</exclude>
+                  <exclude>**/.settings/**</exclude>
+                  <exclude>**/.metadata/</exclude>
+                  <exclude>**/.classpath</exclude>
                   <exclude>**/service.properties</exclude>
                   <exclude>**/kv1.dat</exclude>
                   <exclude>**/*.lck</exclude>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
index eb85bc7..b55a9a2 100644
--- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
@@ -62,6 +62,7 @@ import org.apache.sentry.binding.hive.authz.HiveAuthzPrivilegesMap;
 import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
 import org.apache.sentry.core.common.Action;
 import org.apache.sentry.core.common.Subject;
+import org.apache.sentry.core.common.utils.PathUtils;
 import org.apache.sentry.core.model.db.AccessURI;
 import org.apache.sentry.core.model.db.Database;
 import org.apache.sentry.core.model.db.DBModelAction;
@@ -247,41 +248,16 @@ implements HiveDriverFilterHook {
   @VisibleForTesting
   protected static AccessURI parseURI(String uri, boolean isLocal)
       throws SemanticException {
-    if (!(uri.startsWith("file://") || uri.startsWith("hdfs://"))) {
-      if (uri.startsWith("file:")) {
-        uri = uri.replace("file:", "file://");
-      } else if (uri.startsWith("/")) {
-        String wareHouseDir = SessionState.get().getConf()
-            .get(ConfVars.METASTOREWAREHOUSE.varname);
-        if (wareHouseDir.startsWith("hdfs:")) {
-          URI warehouse = toDFSURI(wareHouseDir);
-          uri = warehouse.getScheme() + "://" + warehouse.getAuthority() + uri;
-        } else if (wareHouseDir.startsWith("file:")) {
-          uri = "file://" + uri;
-        } else {
-          if (isLocal) {
-            uri = "file://" + uri;
-          } else {
-            uri = "hdfs://" + uri;
-          }
-        }
-      }
-      return new AccessURI(uri);
-    }
-    return new AccessURI(uri);
-  }
-
-    private static URI toDFSURI(String s) throws SemanticException {
     try {
-      URI uri = new URI(s);
-      if(uri.getScheme() == null || uri.getAuthority() == null) {
-        throw new SemanticException("Invalid URI " + s + ". No scheme or authority.");
-      }
-      return uri;
-    } catch (URISyntaxException e) {
-      throw new SemanticException("Invalid URI " + s, e);
+      HiveConf conf = SessionState.get().getConf();
+      String warehouseDir = conf.getVar(ConfVars.METASTOREWAREHOUSE);
+      return new AccessURI(PathUtils.parseDFSURI(warehouseDir, uri, isLocal));
+    } catch (Exception e) {
+      throw new SemanticException("Error parsing URI " + uri + ": " +
+        e.getMessage(), e);
     }
   }
+
   /**
    * Post analyze hook that invokes hive auth bindings
    */
@@ -366,6 +342,14 @@ implements HiveDriverFilterHook {
       }
 
       for(ReadEntity readEntity:inputs) {
+      	 // If this is a UDF, then check whether its allowed to be executed
+         // TODO: when we support execute privileges on UDF, this can be removed.
+        if (isUDF(readEntity)) {
+          if (isBuiltinUDF(readEntity)) {
+            checkUDFWhiteList(readEntity.getUDF().getDisplayName());
+          }
+          continue;
+        }
         List<DBModelAuthorizable> entityHierarchy = new ArrayList<DBModelAuthorizable>();
         entityHierarchy.add(hiveAuthzBinding.getAuthServer());
         entityHierarchy.addAll(getAuthzHierarchyFromEntity(readEntity));
@@ -456,7 +440,7 @@ implements HiveDriverFilterHook {
   private boolean isUDF(ReadEntity readEntity) {
     return readEntity.getType().equals(Type.UDF);
   }
-  
+
   private boolean isBuiltinUDF(ReadEntity readEntity) {
     return readEntity.getType().equals(Type.UDF) &&
         readEntity.getUDF().isNative();
@@ -525,19 +509,19 @@ implements HiveDriverFilterHook {
       if (writeEntity.getTyp().equals(Type.DFS_DIR)
           || writeEntity.getTyp().equals(Type.LOCAL_DIR)) {
         HiveConf conf = SessionState.get().getConf();
-        String scratchDirPath = conf.getVar(HiveConf.ConfVars.SCRATCHDIR);
-        if (!scratchDirPath.endsWith(File.pathSeparator)) {
-          scratchDirPath = scratchDirPath + File.pathSeparator;
-        }
-        if (writeEntity.getLocation().getPath().startsWith(scratchDirPath)) {
+        String warehouseDir = conf.getVar(ConfVars.METASTOREWAREHOUSE);
+        URI scratchURI = new URI(PathUtils.parseDFSURI(warehouseDir,
+          conf.getVar(HiveConf.ConfVars.SCRATCHDIR)));
+        URI requestURI = new URI(PathUtils.parseDFSURI(warehouseDir,
+          writeEntity.getLocation().getPath()));
+        LOG.debug("scratchURI = " + scratchURI + ", requestURI = " + requestURI);
+        if (PathUtils.impliesURI(scratchURI, requestURI)) {
           return true;
         }
-
-        String localScratchDirPath = conf.getVar(HiveConf.ConfVars.LOCALSCRATCHDIR);
-        if (!scratchDirPath.endsWith(File.pathSeparator)) {
-          localScratchDirPath = localScratchDirPath + File.pathSeparator;
-        }
-        if (writeEntity.getLocation().getPath().startsWith(localScratchDirPath)) {
+        URI localScratchURI = new URI(PathUtils.parseLocalURI(conf.getVar(HiveConf.ConfVars.LOCALSCRATCHDIR)));
+        URI localRequestURI = new URI(PathUtils.parseLocalURI(writeEntity.getLocation().getPath()));
+        LOG.debug("localScratchURI = " + localScratchURI + ", localRequestURI = " + localRequestURI);
+        if (PathUtils.impliesURI(localScratchURI, localRequestURI)) {
           return true;
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/conf/HiveAuthzConf.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/conf/HiveAuthzConf.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/conf/HiveAuthzConf.java
index 2d562a5..b7d79d6 100644
--- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/conf/HiveAuthzConf.java
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/conf/HiveAuthzConf.java
@@ -91,7 +91,7 @@ public class HiveAuthzConf extends Configuration {
 
   private static final String HIVE_UDF_WHITE_LIST =
     "abs,acos,and,array,array_contains,ascii,asin,assert_true,atan,avg," +
-    "between,bin,case,ceil,ceiling,coalesce,collect_set,compute_stats,concat,concat_ws," +
+    "between,bin,case,cast,ceil,ceiling,coalesce,collect_set,compute_stats,concat,concat_ws," +
     "context_ngrams,conv,corr,cos,count,covar_pop,covar_samp,create_union,date_add,date_sub," +
     "datediff,day,dayofmonth,degrees,div,e,elt,ewah_bitmap,ewah_bitmap_and,ewah_bitmap_empty," +
     "ewah_bitmap_or,exp,explode,field,find_in_set,floor,format_number,from_unixtime," +

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/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 995f376..c6ce53e 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
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.hadoop.conf.Configuration;
@@ -32,6 +33,7 @@ import org.apache.sentry.binding.solr.conf.SolrAuthzConf;
 import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars;
 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.slf4j.Logger;
@@ -54,10 +56,12 @@ public class SolrAuthzBinding {
 
   private final SolrAuthzConf authzConf;
   private final AuthorizationProvider authProvider;
+  private final GroupMappingService groupMapping;
 
   public SolrAuthzBinding (SolrAuthzConf authzConf) throws Exception {
     this.authzConf = authzConf;
     this.authProvider = getAuthProvider();
+    this.groupMapping = authProvider.getGroupMapping();
   }
 
   // Instantiate the configured authz provider
@@ -122,6 +126,15 @@ public class SolrAuthzBinding {
     }
   }
 
+  /**
+   * Get the list of groups the user belongs to
+   * @param user
+   * @return list of groups the user belongs to
+   */
+  public List<String> getGroups(String user) {
+    return groupMapping.getGroups(user);
+  }
+
   private Configuration getConf() throws IOException {
     Configuration conf = new Configuration();
     String confDir = System.getProperty("solr.hdfs.confdir");

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/TestSolrAuthzBinding.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/TestSolrAuthzBinding.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/TestSolrAuthzBinding.java
index 494a430..b061eec 100644
--- a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/TestSolrAuthzBinding.java
+++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/TestSolrAuthzBinding.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.lang.reflect.InvocationTargetException;
 
 import junit.framework.Assert;
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
 import org.apache.commons.io.FileUtils;
@@ -161,6 +162,33 @@ public class TestSolrAuthzBinding {
   }
 
   /**
+   * Test for group mapping
+   */
+  @Test
+  public void testGroupMapping() throws Exception {
+    SolrAuthzConf solrAuthzConf =
+      new SolrAuthzConf(Resources.getResource("sentry-site.xml"));
+    setUsableAuthzConf(solrAuthzConf);
+    SolrAuthzBinding binding = new SolrAuthzBinding(solrAuthzConf);
+    List<String> emptyList = Arrays.asList();
+
+    // check non-existant users
+    assertEquals(binding.getGroups(null), emptyList);
+    assertEquals(binding.getGroups("nonExistantUser"), emptyList);
+
+    // check group names don't map to user names
+    assertEquals(binding.getGroups("corporal"), emptyList);
+    assertEquals(binding.getGroups("sergeant"), emptyList);
+    assertEquals(binding.getGroups("general"), emptyList);
+    assertEquals(binding.getGroups("othergeneralgroup"), emptyList);
+
+    // check valid group names
+    assertEquals(binding.getGroups("corporal1"), Arrays.asList("corporal"));
+    assertEquals(binding.getGroups("sergeant1"), Arrays.asList("sergeant"));
+    assertEquals(binding.getGroups("general1"), Arrays.asList("general", "othergeneralgroup"));
+  }
+
+  /**
    * Test that a full sentry-site definition works.
    */
   @Test

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-binding/sentry-binding-solr/src/test/resources/test-authz-provider.ini
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/test/resources/test-authz-provider.ini b/sentry-binding/sentry-binding-solr/src/test/resources/test-authz-provider.ini
index db9af6e..f8100e0 100644
--- a/sentry-binding/sentry-binding-solr/src/test/resources/test-authz-provider.ini
+++ b/sentry-binding/sentry-binding-solr/src/test/resources/test-authz-provider.ini
@@ -30,4 +30,4 @@ general_role = collection=*->action=*
 [users]
 corporal1=corporal
 sergeant1=sergeant
-general1=general
\ No newline at end of file
+general1=general, othergeneralgroup
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-core/sentry-core-common/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/pom.xml b/sentry-core/sentry-core-common/pom.xml
index 9b7d067..a14f129 100644
--- a/sentry-core/sentry-core-common/pom.xml
+++ b/sentry-core/sentry-core-common/pom.xml
@@ -27,4 +27,16 @@ limitations under the License.
   <artifactId>sentry-core-common</artifactId>
   <name>Sentry Core Common</name>
 
+  <dependencies>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java
new file mode 100644
index 0000000..1659450
--- /dev/null
+++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java
@@ -0,0 +1,131 @@
+/*
+ * 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.core.common.utils;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.google.common.base.Strings;
+
+public class PathUtils {
+  /**
+   * URI is a a special case. For URI's, /a implies /a/b.
+   * Therefore the test is "/a/b".startsWith("/a");
+   */
+  public static boolean impliesURI(URI privilegeURI, URI requestURI)
+    throws URISyntaxException {
+    if (privilegeURI.getPath() == null || requestURI.getPath() == null) {
+      return false;
+    }
+    // ensure that either both schemes are null or equal
+    if (privilegeURI.getScheme() == null) {
+      if (requestURI.getScheme() != null) {
+        return false;
+      }
+    } else if (!privilegeURI.getScheme().equals(requestURI.getScheme())) {
+      return false;
+    }
+    // request path does not contain relative parts /a/../b &&
+    // request path starts with privilege path &&
+    // authorities (nullable) are equal
+    String requestPath = ensureEndsWithSeparator(requestURI.getPath());
+    String privilegePath = ensureEndsWithSeparator(privilegeURI.getPath());
+    if (requestURI.getPath().equals(requestURI.normalize().getPath()) &&
+        requestPath.startsWith(privilegePath) &&
+        Strings.nullToEmpty(privilegeURI.getAuthority()).equals(Strings.nullToEmpty(requestURI.getAuthority()))) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * The URI must be a directory as opposed to a partial
+   * path entry name. To ensure this is true we add a /
+   * at the end of the path. Without this the admin might
+   * grant access to /dir1 but the user would be given access
+   * to /dir1* whereas the admin meant /dir1/
+   */
+  private static String ensureEndsWithSeparator(String path) {
+    if (path.endsWith(File.separator)) {
+      return path;
+    }
+    return path + File.separator;
+  }
+
+  public static String parseDFSURI(String warehouseDir, String uri)
+      throws URISyntaxException {
+    return parseDFSURI(warehouseDir, uri, false);
+  }
+
+  /**
+   * Parse a URI which should be on HDFS in the normal case but can be on a local
+   * file system in the testing case. In either case it should be on the same fs
+   * as the warehouse directory.
+   */
+  public static String parseDFSURI(String warehouseDir, String uri, boolean isLocal)
+      throws URISyntaxException {
+    if ((uri.startsWith("file://") || uri.startsWith("hdfs://"))) {
+      return uri;
+    } else {
+      if (uri.startsWith("file:")) {
+        uri = uri.replace("file:", "file://");
+      } else if (uri.startsWith("/")) {
+        if (warehouseDir.startsWith("hdfs:")) {
+          URI warehouse = toDFSURI(warehouseDir);
+          uri = warehouse.getScheme() + "://" + warehouse.getAuthority() + uri;
+        } else if (warehouseDir.startsWith("file:")) {
+          uri = "file://" + uri;
+        } else {
+          if (isLocal) {
+            uri = "file://" + uri;
+          } else {
+            // TODO fix this logic. I don't see why we would want to add hdfs://
+            // to a URI at this point in time since no namenode is specified
+            // and warehouseDir appear to just be a path starting with / ?
+            // I think in the isLocal = false case we might want to throw
+            uri = "hdfs://" + uri;
+          }
+        }
+      }
+      return uri;
+    }
+  }
+
+  /**
+   * Parse a URI which is on a local file system.
+   */
+  public static String parseLocalURI(String uri)
+      throws URISyntaxException {
+    if (uri.startsWith("file://")) {
+      return uri;
+    } else if (uri.startsWith("file:")) {
+      return uri.replace("file:", "file://");
+    } else if (uri.startsWith("/")) {
+      return "file://" + uri;
+    }
+    throw new IllegalStateException("Parse URI does not work on relative URI: " + uri);
+  }
+
+  private static URI toDFSURI(String s) throws URISyntaxException {
+    URI uri = new URI(s);
+    if(uri.getScheme() == null || uri.getAuthority() == null) {
+      throw new IllegalArgumentException("Invalid URI " + s + ". No scheme or authority.");
+    }
+    return uri;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java b/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java
new file mode 100644
index 0000000..28818ba
--- /dev/null
+++ b/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java
@@ -0,0 +1,76 @@
+/*
+ * 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.core.common.utils;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import java.net.URI;
+import org.junit.Test;
+
+public class TestPathUtils {
+
+  @Test
+  public void testNullScheme() throws Exception {
+    assertTrue(PathUtils.impliesURI(new URI("/tmp"), new URI("/tmp/a")));
+    assertFalse(PathUtils.impliesURI(new URI("file:/tmp"), new URI("/tmp/a")));
+    assertFalse(PathUtils.impliesURI(new URI("/tmp"), new URI("file:/tmp/a")));
+    // Privileges on /tmp/ are distinct from /tmp.+/ e.g. /tmp/ and /tmpdata/
+    assertFalse(PathUtils.impliesURI(new URI("/tmp"), new URI("/tmpdata")));
+  }
+
+  @Test
+  public void testParseDFSURI() throws Exception {
+    // warehouse hdfs, path /
+    assertEquals("hdfs://namenode:8020/tmp/hive-user", PathUtils.
+      parseDFSURI("hdfs://namenode:8020/user/hive/warehouse", "/tmp/hive-user"));
+    // warehouse hdfs, path hdfs
+    assertEquals("hdfs://namenode:8020/tmp/hive-user", PathUtils.
+      parseDFSURI("hdfs://namenode:8020/user/hive/warehouse", "hdfs://namenode:8020/tmp/hive-user"));
+
+    // warehouse file:///, path /
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:///tmp/hive-warehouse", "/tmp/hive-user"));
+    // warehouse file:///, path file:/
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:///tmp/hive-warehouse", "file:/tmp/hive-user"));
+    // warehouse file:///, path file:///
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:///tmp/hive-warehouse", "file:///tmp/hive-user"));
+
+    // warehouse file:/, path /
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:/tmp/hive-warehouse", "/tmp/hive-user"));
+    // warehouse file:/, path file:/
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:/tmp/hive-warehouse", "file:/tmp/hive-user"));
+    // warehouse file:/, path file:///
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseDFSURI("file:/tmp/hive-warehouse", "file:///tmp/hive-user"));
+  }
+
+  @Test
+  public void testParseLocalURI() throws Exception {
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseLocalURI("/tmp/hive-user"));
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseLocalURI("file:/tmp/hive-user"));
+    assertEquals("file:///tmp/hive-user", PathUtils.
+      parseLocalURI("file:///tmp/hive-user"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-dist/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-dist/pom.xml b/sentry-dist/pom.xml
index aa2185a..b783b09 100644
--- a/sentry-dist/pom.xml
+++ b/sentry-dist/pom.xml
@@ -85,7 +85,7 @@ limitations under the License.
             </goals>
             <inherited>false</inherited>
             <configuration>
-              <finalName>sentry-${project.version}</finalName>
+              <finalName>apache-sentry-${project.version}</finalName>
               <descriptors>
                 <descriptor>src/main/assembly/src.xml</descriptor>
               </descriptors>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-dist/src/main/assembly/src.xml
----------------------------------------------------------------------
diff --git a/sentry-dist/src/main/assembly/src.xml b/sentry-dist/src/main/assembly/src.xml
index 3d2e5ee..a06e521 100644
--- a/sentry-dist/src/main/assembly/src.xml
+++ b/sentry-dist/src/main/assembly/src.xml
@@ -22,109 +22,46 @@
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
 
-  <id>dist</id>
+  <id>src</id>
 
   <formats>
     <format>tar.gz</format>
   </formats>
 
-  <baseDirectory>sentry-${project.version}</baseDirectory>
+  <baseDirectory>apache-sentry-${project.version}-src</baseDirectory>
 
-  <moduleSets>
-
-    <moduleSet>
-      <useAllReactorProjects>true</useAllReactorProjects>
-
-      <includes>
-        <include>org.apache.sentry:sentry-binding</include>
-        <include>org.apache.sentry:sentry-binding-hive</include>
-        <include>org.apache.sentry:sentry-binding-solr</include>
-        <include>org.apache.sentry:sentry-core</include>
-        <include>org.apache.sentry:sentry-core-common</include>
-        <include>org.apache.sentry:sentry-core-model-db</include>
-        <include>org.apache.sentry:sentry-core-model-search</include>
-        <include>org.apache.sentry:sentry-provider</include>
-        <include>org.apache.sentry:sentry-provider-common</include>
-        <include>org.apache.sentry:sentry-provider-file</include>
-        <include>org.apache.sentry:sentry-provider-db</include>
-        <include>org.apache.sentry:sentry-policy</include>
-        <include>org.apache.sentry:sentry-policy-common</include>
-        <include>org.apache.sentry:sentry-policy-db</include>
-        <include>org.apache.sentry:sentry-policy-search</include>
-        <include>org.apache.sentry:sentry-tests</include>
-        <include>org.apache.sentry:sentry-tests-hive</include>
-        <include>org.apache.sentry:sentry-dist</include>
-      </includes>
-
-      <binaries>
-        <unpack>false</unpack>
-        <outputDirectory>lib</outputDirectory>
-
-        <dependencySets>
-          <dependencySet>
-            <useProjectArtifact>false</useProjectArtifact>
-            <outputDirectory>lib</outputDirectory>
-          </dependencySet>
-        </dependencySets>
-      </binaries>
-
-      <sources>
-        <includeModuleDirectory>true</includeModuleDirectory>
-        <excludeSubModuleDirectories>false</excludeSubModuleDirectories>
-
-        <fileSets>
-          <fileSet>
-            <excludes>
-              <exclude>target/**</exclude>
-              <exclude>*/target/**</exclude>
-              <exclude>.classpath</exclude>
-              <exclude>*/.classpath</exclude>
-              <exclude>.project</exclude>
-              <exclude>*/.project</exclude>
-              <exclude>.settings/**</exclude>
-              <exclude>*/.settings/**</exclude>
-            </excludes>
-          </fileSet>
-        </fileSets>
-      </sources>
-
-    </moduleSet>
-
-  </moduleSets>
   <fileSets>
     <fileSet>
-      <directory>../</directory>
+      <directory>${project.parent.basedir}</directory>
 
       <excludes>
-        <exclude>sentry-binding/**</exclude>
-        <exclude>sentry-core/**</exclude>
-        <exclude>sentry-dist/**</exclude>
-        <exclude>sentry-provider/**</exclude>
-        <exclude>sentry-policy/**</exclude>
-        <exclude>sentry-test/**</exclude>
         <exclude>**/target/**</exclude>
         <exclude>**/.classpath</exclude>
         <exclude>**/.project</exclude>
         <exclude>**/.settings/**</exclude>
-        <exclude>lib/**</exclude>
+        <exclude>sentry-tests/sentry-tests-hive/thirdparty/**</exclude>
       </excludes>
 
       <includes>
-        <include>.gitignore</include>
+        <include>bin/**</include>
+        <include>**/.gitignore</include>
         <include>conf/**</include>
         <include>pom.xml</include>
-        <include>LICENSE.txt</include>
-        <include>NOTICE</include>
-      </includes>
-    </fileSet>
-    <fileSet>
-      <directory>../</directory>
-      <fileMode>755</fileMode>
-      <includes>
-        <include>bin/**</include>
+        <include>CHANGELOG*</include>
+        <include>DISCLAIMER*</include>
+        <include>LICENSE*</include>
+        <include>NOTICE*</include>
+        <include>README*</include>
+        <include>dev-support/**</include>
+        <include>sentry-binding/**</include>
+        <include>sentry-core/**</include>
+        <include>sentry-dist/**</include>
+        <include>sentry-provider/**</include>
+        <include>sentry-policy/**</include>
+        <include>sentry-tests/**</include>
       </includes>
+      <outputDirectory>/</outputDirectory>
     </fileSet>
   </fileSets>
 
 </assembly>
-

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java
index e84e5b9..01981d1 100644
--- a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java
+++ b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java
@@ -24,13 +24,13 @@ package org.apache.sentry.policy.db;
 import static org.apache.sentry.provider.file.PolicyFileConstants.AUTHORIZABLE_JOINER;
 import static org.apache.sentry.provider.file.PolicyFileConstants.AUTHORIZABLE_SPLITTER;
 
-import java.io.File;
 import java.io.Serializable;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
 
 import org.apache.commons.lang.text.StrSubstitutor;
+import org.apache.sentry.core.common.utils.PathUtils;
 import org.apache.sentry.core.model.db.AccessConstants;
 import org.apache.sentry.core.model.db.DBModelAuthorizable.AuthorizableType;
 import org.apache.sentry.policy.common.PermissionFactory;
@@ -133,36 +133,20 @@ public class DBWildcardPermission implements Permission, Serializable {
     return false;
   }
 
-  /**
-   * URI is a a special case. For URI's, /a implies /a/b.
-   * Therefore the test is "/a/b".startsWith("/a");
-   */
   @VisibleForTesting
-  protected static boolean impliesURI(String policy, String request) {
+  protected static boolean impliesURI(String privilege, String request) {
     try {
-      URI policyURI = new URI(new StrSubstitutor(System.getProperties()).replace(policy));
-      URI requestURI = new URI(request);
-      if(policyURI.getScheme() == null || policyURI.getPath() == null) {
-        LOGGER.warn("Policy URI " + policy + " is not valid. Either no scheme or no path.");
-        return false;
-      }
-      if(requestURI.getScheme() == null || requestURI.getPath() == null) {
-        LOGGER.warn("Request URI " + request + " is not valid. Either no scheme or no path.");
-        return false;
-      }
-      // schemes are equal &&
-      // request path does not contain relative parts /a/../b &&
-      // request path starts with policy path &&
-      // authorities (nullable) are equal
-      String requestPath = requestURI.getPath() + File.separator;
-      String policyPath = policyURI.getPath() + File.separator;
-      if(policyURI.getScheme().equals(requestURI.getScheme()) &&
-          requestURI.getPath().equals(new URI(request).normalize().getPath()) &&
-          requestPath.startsWith(policyPath) &&
-          Strings.nullToEmpty(policyURI.getAuthority()).equals(Strings.nullToEmpty(requestURI.getAuthority()))) {
-        return true;
-      }
+    URI privilegeURI = new URI(new StrSubstitutor(System.getProperties()).replace(privilege));
+    URI requestURI = new URI(request);
+    if(privilegeURI.getScheme() == null || privilegeURI.getPath() == null) {
+      LOGGER.warn("Privilege URI " + request + " is not valid. Either no scheme or no path.");
+      return false;
+    }
+    if(requestURI.getScheme() == null || requestURI.getPath() == null) {
+      LOGGER.warn("Request URI " + request + " is not valid. Either no scheme or no path.");
       return false;
+    }
+      return PathUtils.impliesURI(privilegeURI, requestURI);
     } catch (URISyntaxException e) {
       LOGGER.warn("Request URI " + request + " is not a URI", e);
       return false;

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-policy/sentry-policy-db/src/test/java/org/apache/sentry/policy/db/TestDBWildcardPermission.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-db/src/test/java/org/apache/sentry/policy/db/TestDBWildcardPermission.java b/sentry-policy/sentry-policy-db/src/test/java/org/apache/sentry/policy/db/TestDBWildcardPermission.java
index 8f1ee2c..2024cd8 100644
--- a/sentry-policy/sentry-policy-db/src/test/java/org/apache/sentry/policy/db/TestDBWildcardPermission.java
+++ b/sentry-policy/sentry-policy-db/src/test/java/org/apache/sentry/policy/db/TestDBWildcardPermission.java
@@ -51,7 +51,7 @@ public class TestDBWildcardPermission {
           "hdfs://namenode:8020/path/to/uri1"));
   private static final Permission ROLE_SERVER_SERVER1_URI_URI2 =
       create(new KeyValue("server", "server1"), new KeyValue("uri",
-          "hdfs://namenode:8020/path/to/uri2"));
+          "hdfs://namenode:8020/path/to/uri2/"));
   private static final Permission ROLE_SERVER_SERVER1_URI_ALL =
       create(new KeyValue("server", "server1"), new KeyValue("uri", ALL));
 
@@ -272,6 +272,9 @@ public class TestDBWildcardPermission {
     // mangled path
     assertFalse(DBWildcardPermission.impliesURI("hdfs://namenode:8020/path",
         "hdfs://namenode:8020/pathFooBar"));
+    // ends in /
+    assertTrue(DBWildcardPermission.impliesURI("hdfs://namenode:8020/path/",
+        "hdfs://namenode:8020/path/FooBar"));
   }
   static DBWildcardPermission create(KeyValue... keyValues) {
     return create(AUTHORIZABLE_JOINER.join(keyValues));

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-common/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/pom.xml b/sentry-provider/sentry-provider-common/pom.xml
index 321f7c6..1e9dc1b 100644
--- a/sentry-provider/sentry-provider-common/pom.xml
+++ b/sentry-provider/sentry-provider-common/pom.xml
@@ -29,6 +29,11 @@ limitations under the License.
 
   <dependencies>
     <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.sentry</groupId>
       <artifactId>sentry-core-common</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationProvider.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationProvider.java b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationProvider.java
index 4351c3f..1244755 100644
--- a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationProvider.java
+++ b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/AuthorizationProvider.java
@@ -38,4 +38,10 @@ public interface AuthorizationProvider {
    */
   public boolean hasAccess(Subject subject, List<? extends Authorizable> authorizableHierarchy, Set<? extends Action> actions);
 
+  /***
+   * Get the GroupMappingService used by the AuthorizationProvider
+   *
+   * @return GroupMappingService used by the AuthorizationProvider
+   */
+  public GroupMappingService getGroupMapping();
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoAuthorizationProvider.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoAuthorizationProvider.java b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoAuthorizationProvider.java
index 9cdda97..f48eafe 100644
--- a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoAuthorizationProvider.java
+++ b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoAuthorizationProvider.java
@@ -24,6 +24,7 @@ import org.apache.sentry.core.common.Authorizable;
 import org.apache.sentry.core.common.Subject;
 
 public class NoAuthorizationProvider implements AuthorizationProvider {
+  private GroupMappingService noGroupMappingService = new NoGroupMappingService();
 
   @Override
   public boolean hasAccess(Subject subject, List<? extends Authorizable> authorizableHierarchy,
@@ -31,4 +32,8 @@ public class NoAuthorizationProvider implements AuthorizationProvider {
     return false;
   }
 
+  @Override
+  public GroupMappingService getGroupMapping() {
+    return noGroupMappingService;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoGroupMappingService.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoGroupMappingService.java b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoGroupMappingService.java
new file mode 100644
index 0000000..e1bc6d2
--- /dev/null
+++ b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/NoGroupMappingService.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * GroupMappingService that always returns an empty list of groups
+ */
+public class NoGroupMappingService implements GroupMappingService {
+
+  /**
+   * @return empty list of groups for every user
+   */
+  public List<String> getGroups(String user) {
+    return new LinkedList<String>();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-common/src/test/java/org/apache/sentry/provider/common/TestNoAuthorizationProvider.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/test/java/org/apache/sentry/provider/common/TestNoAuthorizationProvider.java b/sentry-provider/sentry-provider-common/src/test/java/org/apache/sentry/provider/common/TestNoAuthorizationProvider.java
new file mode 100644
index 0000000..3f48f49
--- /dev/null
+++ b/sentry-provider/sentry-provider-common/src/test/java/org/apache/sentry/provider/common/TestNoAuthorizationProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Tests around the NoAuthorizationProvider
+ */
+public class TestNoAuthorizationProvider {
+
+  @Test
+  public void testNoAuthorizationProvider() {
+    NoAuthorizationProvider nap = new NoAuthorizationProvider();
+    assertFalse(nap.hasAccess(null, null, null));
+
+    GroupMappingService gms = nap.getGroupMapping();
+    assertEquals(gms.getGroups(null).size(), 0);
+    assertEquals(gms.getGroups("").size(), 0);
+    assertEquals(gms.getGroups("a").size(), 0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
index af38ee7..85d5085 100644
--- a/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-mysql-1.4.0.sql
@@ -1,3 +1,19 @@
+--Licensed to the Apache Software Foundation (ASF) under one or more
+--contributor license agreements.  See the NOTICE file distributed with
+--this work for additional information regarding copyright ownership.
+--The ASF licenses this file to You under the Apache License, Version 2.0
+--(the "License"); you may not use this file except in compliance with
+--the License.  You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+--Unless required by applicable law or agreed to in writing, software
+--distributed under the License is distributed on an "AS IS" BASIS,
+--WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--See the License for the specific language governing permissions and
+--limitations under the License.
+
+
 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
index 95c8907..0508d45 100644
--- a/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-oracle-1.4.0.sql
@@ -1,3 +1,18 @@
+--Licensed to the Apache Software Foundation (ASF) under one or more
+--contributor license agreements.  See the NOTICE file distributed with
+--this work for additional information regarding copyright ownership.
+--The ASF licenses this file to You under the Apache License, Version 2.0
+--(the "License"); you may not use this file except in compliance with
+--the License.  You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+--Unless required by applicable law or agreed to in writing, software
+--distributed under the License is distributed on an "AS IS" BASIS,
+--WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--See the License for the specific language governing permissions and
+--limitations under the License.
+
 CREATE TABLE "SENTRY_DB_PRIVILEGE" (
   "DB_PRIVILEGE_ID" NUMBER NOT NULL,
   "PRIVILEGE_NAME" VARCHAR2(128) NOT NULL, -- Name of the privilege

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql b/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
index 9dd0a00..7298923 100644
--- a/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
+++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry-postgres-1.4.0.sql
@@ -1,3 +1,18 @@
+--Licensed to the Apache Software Foundation (ASF) under one or more
+--contributor license agreements.  See the NOTICE file distributed with
+--this work for additional information regarding copyright ownership.
+--The ASF licenses this file to You under the Apache License, Version 2.0
+--(the "License"); you may not use this file except in compliance with
+--the License.  You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+--Unless required by applicable law or agreed to in writing, software
+--distributed under the License is distributed on an "AS IS" BASIS,
+--WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--See the License for the specific language governing permissions and
+--limitations under the License.
+
 START TRANSACTION;
 
 SET statement_timeout = 0;

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-file/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-file/pom.xml b/sentry-provider/sentry-provider-file/pom.xml
index a804952..60c4836 100644
--- a/sentry-provider/sentry-provider-file/pom.xml
+++ b/sentry-provider/sentry-provider-file/pom.xml
@@ -29,6 +29,10 @@ limitations under the License.
 
   <dependencies>
     <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-common</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/ResourceAuthorizationProvider.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/ResourceAuthorizationProvider.java b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/ResourceAuthorizationProvider.java
index c7d983d..205d012 100644
--- a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/ResourceAuthorizationProvider.java
+++ b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/ResourceAuthorizationProvider.java
@@ -116,4 +116,9 @@ public abstract class ResourceAuthorizationProvider implements AuthorizationProv
       }
     });
   }
+
+  @Override
+  public GroupMappingService getGroupMapping() {
+    return groupService;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestGetGroupMapping.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestGetGroupMapping.java b/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestGetGroupMapping.java
new file mode 100644
index 0000000..a4d4bb3
--- /dev/null
+++ b/sentry-provider/sentry-provider-file/src/test/java/org/apache/sentry/provider/file/TestGetGroupMapping.java
@@ -0,0 +1,54 @@
+/*
+ * 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.file;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.policy.common.PermissionFactory;
+import org.apache.sentry.policy.common.PolicyEngine;
+import org.apache.sentry.provider.common.GroupMappingService;
+import com.google.common.collect.ImmutableSetMultimap;
+import org.junit.Test;
+import static org.junit.Assert.assertSame;
+
+public class TestGetGroupMapping {
+
+  private static class TestResourceAuthorizationProvider extends ResourceAuthorizationProvider {
+    public TestResourceAuthorizationProvider(PolicyEngine policy,
+      GroupMappingService groupService) {
+      super(policy, groupService);
+    }
+  };
+
+  @Test
+  public void testResourceAuthorizationProvider() {
+    final List<String> list = Arrays.asList("a", "b", "c");
+    GroupMappingService mappingService = new GroupMappingService() {
+      public List<String> getGroups(String user) { return list; }
+    };
+    PolicyEngine policyEngine = new PolicyEngine() {
+      public PermissionFactory getPermissionFactory() { return null; }
+
+      public ImmutableSetMultimap<String, String> getPermissions(List<? extends Authorizable> authorizables, List<String> groups) { return null; }
+    };
+
+    TestResourceAuthorizationProvider authProvider =
+      new TestResourceAuthorizationProvider(policyEngine, mappingService);
+    assertSame(authProvider.getGroupMapping(), mappingService);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
index 82d73e5..8c145ca 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
@@ -107,6 +107,10 @@ public class TestPrivilegesAtDatabaseScope extends AbstractTestWithStaticConfigu
     statement.execute("CREATE TABLE DB_1.TAB_2(A STRING)");
     statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE DB_1.TAB_2");
 
+    // test CTAS can reference UDFs
+    statement.execute("USE DB_1");
+    statement.execute("create table table2 as select A, count(A) from TAB_1 GROUP BY A");
+    
     // test user can switch db
     statement.execute("USE DB_1");
     //test user can create view

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
index badd523..be6eafc 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
@@ -76,7 +76,7 @@ public abstract class AbstractHiveServer implements HiveServer {
       }
       try {
         DriverManager.setLoginTimeout(30);
-        Connection connection =  DriverManager.getConnection(hiveServer.getURL(), "hive", "bar");
+        Connection connection =  DriverManager.getConnection(hiveServer.getURL(), "foo", "bar");
         connection.close();
         break;
       } catch (SQLException e) {

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/22b6a348/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..7819114 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>
@@ -33,6 +41,10 @@ limitations under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.solr</groupId>
+      <artifactId>solr-sentry-handlers</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.solr</groupId>
       <artifactId>solr-solrj</artifactId>
     </dependency>
     <dependency>
@@ -46,7 +58,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/22b6a348/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..05c5263 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,10 @@ package org.apache.sentry.tests.e2e.solr;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Collections;
 import java.util.Comparator;
+import java.util.Random;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -27,11 +30,25 @@ 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.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.cloud.ZkController;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CollectionParams.CollectionAction;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.NamedList;
 import org.apache.solr.servlet.SolrDispatchFilter;
 
+import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -41,8 +58,12 @@ 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 String ALL_DOCS = "*:*";
+  protected static final Random RANDOM = new Random();
 
   private static void addPropertyToSentry(StringBuilder builder, String name, String value) {
     builder.append("<property>\n");
@@ -92,7 +113,7 @@ public abstract class AbstractSolrSentryTestBase extends AbstractFullDistribZkTe
         return true;
       }
     });
-    extraRequestFilters.put(JunitAuthenticationFilter.class, "*");
+    extraRequestFilters.put(ModifiableUserAuthenticationFilter.class, "*");
   }
 
   @AfterClass
@@ -104,17 +125,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 +160,530 @@ 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);
+  }
+
+  /**
+   * Get the user defined in the Solr authentication filter
+   * @return - the username as String
+   * @throws Exception
+   */
+  private String getAuthenticatedUser() throws Exception {
+    return ModifiableUserAuthenticationFilter.getUser();
+  }
+
+  /**
+   * 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 {
+    String originalUser = getAuthenticatedUser();
+    try {
+      SolrDocumentList orginalSolrDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      setAuthenticationUser(solrUserName);
+      CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+      try {
+        cloudSolrServer.add(solrInputDoc);
+        cloudSolrServer.commit();
+      } finally {
+        cloudSolrServer.shutdown();
+      }
+
+      orginalSolrDocs.add(ClientUtils.toSolrDocument(solrInputDoc));
+      SolrDocumentList solrRespDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      // Validate Solr content to check whether the update command went through.
+      validateSolrDocCountAndContent(orginalSolrDocs, solrRespDocs);
+    }
+    finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * 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 {
+    String originalUser = getAuthenticatedUser();
+    try {
+      SolrDocumentList orginalSolrDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      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();
+      }
+
+      SolrDocumentList solrRespDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      // Validate Solr content to check whether the update command didn't go through.
+      validateSolrDocCountAndContent(orginalSolrDocs, solrRespDocs);
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * 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 {
+    String originalUser = getAuthenticatedUser();
+    try {
+      SolrDocumentList orginalSolrDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      if (allowZeroDocs == false) {
+        assertTrue("Solr should contain atleast one solr doc to run this test.", orginalSolrDocs.size() > 0);
+      }
+
+      setAuthenticationUser(solrUserName);
+      CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+      try {
+        cloudSolrServer.deleteByQuery(ALL_DOCS);
+        cloudSolrServer.commit();
+      } finally {
+        cloudSolrServer.shutdown();
+      }
+
+      // Validate Solr doc count is zero
+      SolrDocumentList solrRespDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      validateSolrDocCountAndContent(new SolrDocumentList(), solrRespDocs);
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * 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 {
+    String originalUser = getAuthenticatedUser();
+    try {
+      SolrDocumentList orginalSolrDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      if (allowZeroDocs == false) {
+        assertTrue("Solr should contain atleast one solr doc to run this test.", orginalSolrDocs.size() > 0);
+      }
+
+      setAuthenticationUser(solrUserName);
+      CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+      try {
+        cloudSolrServer.deleteByQuery(ALL_DOCS);
+        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 doc count and content is same as original set.
+      SolrDocumentList solrRespDocs = getSolrDocs(collectionName, ALL_DOCS, true);
+      validateSolrDocCountAndContent(orginalSolrDocs, solrRespDocs);
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * Method to validate Solr query passes
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to be queried
+   * @param solrQueryStr - Query string to be searched in Solr
+   * @throws Exception
+   */
+  protected void verifyQueryPass(String solrUserName,
+                                 String collectionName,
+                                 String solrQueryStr) throws Exception {
+    String originalUser = getAuthenticatedUser();
+    try {
+      SolrDocumentList orginalSolrDocs = getSolrDocs(collectionName, solrQueryStr, true);
+      setAuthenticationUser(solrUserName);
+      SolrDocumentList solrRespDocs = null;
+      solrRespDocs = getSolrDocs(collectionName, solrQueryStr, false);
+
+      // Validate Solr content to check whether the query command went through.
+      validateSolrDocCountAndContent(orginalSolrDocs, solrRespDocs);
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * Method to validate Solr query fails
+   * @param solrUserName - User authenticated into Solr
+   * @param collectionName - Name of the collection to be queried
+   * @param solrQueryStr - Query string to be searched in Solr
+   * @throws Exception
+   */
+  protected void verifyQueryFail(String solrUserName,
+                                 String collectionName,
+                                 String solrQueryStr) throws Exception {
+    String originalUser = getAuthenticatedUser();
+    try {
+      setAuthenticationUser(solrUserName);
+      try {
+        getSolrDocs(collectionName, solrQueryStr, false);
+        fail("The specified user: " + solrUserName + " shouldn't get query access!");
+      } catch (Exception exception) {
+        assertTrue("Expected " + SENTRY_ERROR_MSG + " in " + exception.toString(),
+            exception.toString().contains(SENTRY_ERROR_MSG));
+      }
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * Method to validate collection Admin operation pass
+   * @param solrUserName - User authenticated into Solr
+   * @param adminOp - Admin operation to be performed
+   * @param collectionName - Name of the collection to be queried
+   * @param ignoreError - boolean to specify whether to ignore the error if any occurred.
+   *                      (We may need this attribute for running DELETE command on a collection which doesn't exist)
+   * @throws Exception
+   */
+  protected void verifyCollectionAdminOpPass(String solrUserName,
+                                             CollectionAction adminOp,
+                                             String collectionName) throws Exception {
+    String originalUser = getAuthenticatedUser();
+    try {
+      setAuthenticationUser(solrUserName);
+      QueryRequest request = populateCollectionAdminParams(adminOp, collectionName);
+      SolrServer solrServer = createNewSolrServer("", getBaseUrl((HttpSolrServer) clients.get(0)));
+      try {
+        NamedList<Object> result = solrServer.request(request);
+        if (adminOp.compareTo(CollectionAction.CREATE) == 0) {
+          // Wait for collection creation to complete.
+          waitForRecoveriesToFinish(collectionName, false);
+        }
+      } finally {
+        solrServer.shutdown();
+      }
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * Method to validate collection Admin operation fail
+   * @param solrUserName - User authenticated into Solr
+   * @param adminOp - Admin operation to be performed
+   * @param collectionName - Name of the collection to be queried
+   * @throws Exception
+   */
+  protected void verifyCollectionAdminOpFail(String solrUserName,
+                                             CollectionAction adminOp,
+                                             String collectionName) throws Exception {
+
+    String originalUser = getAuthenticatedUser();
+    try {
+      setAuthenticationUser(solrUserName);
+      try {
+        QueryRequest request = populateCollectionAdminParams(adminOp, collectionName);
+        SolrServer solrServer = createNewSolrServer("", getBaseUrl((HttpSolrServer) clients.get(0)));
+        try {
+          NamedList<Object> result = solrServer.request(request);
+          if (adminOp.compareTo(CollectionAction.CREATE) == 0) {
+            // Wait for collection creation to complete.
+            waitForRecoveriesToFinish(collectionName, false);
+          }
+        } finally {
+          solrServer.shutdown();
+        }
+
+        fail("The specified user: " + solrUserName + " shouldn't get admin access for " + adminOp);
+      } catch (Exception exception) {
+        assertTrue("Expected " + SENTRY_ERROR_MSG + " in " + exception.toString(),
+            exception.toString().contains(SENTRY_ERROR_MSG));
+      }
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * Method to populate the Solr params based on the collection admin being performed.
+   * @param adminOp - Collection admin operation
+   * @param collectionName - Name of the collection
+   * @return - instance of QueryRequest.
+   */
+  public QueryRequest populateCollectionAdminParams(CollectionAction adminOp,
+                                                            String collectionName) {
+    ModifiableSolrParams modParams = new ModifiableSolrParams();
+    modParams.set(CoreAdminParams.ACTION, adminOp.name());
+    switch (adminOp) {
+      case CREATE:
+        modParams.set("name", collectionName);
+        modParams.set("numShards", 2);
+        modParams.set("shards", "shard1,shard2");
+        modParams.set("replicationFactor", 1);
+        break;
+      case DELETE:
+        modParams.set("name", collectionName);
+        break;
+      case RELOAD:
+        modParams.set("name", collectionName);
+        break;
+      case SPLITSHARD:
+        modParams.set("collection", collectionName);
+        modParams.set("shard", "shard1");
+        break;
+      case DELETESHARD:
+        modParams.set("collection", collectionName);
+        modParams.set("shard", "shard1");
+        break;
+      case CREATEALIAS:
+        modParams.set("name", collectionName);
+        modParams.set("collections", collectionName + "_underlying1"
+            + "," + collectionName + "_underlying2");
+        break;
+      case DELETEALIAS:
+        modParams.set("name", collectionName);
+        break;
+      default:
+        throw new IllegalArgumentException("Admin operation: " + adminOp + " is not supported!");
+    }
+
+    QueryRequest request = new QueryRequest(modParams);
+    request.setPath("/admin/collections");
+    return request;
+  }
+
+  /**
+   * Function to validate the count and content of two SolrDocumentList's.
+   * @param solrOriginalDocs - Instance of initial set of solr docs before processing
+   * @param solrResponseDocs - Instance of response solr docs after processing
+   */
+  protected void validateSolrDocCountAndContent(SolrDocumentList solrOriginalDocs,
+                                                SolrDocumentList solrResponseDocs) {
+    assertEquals("Expected number of Solr docs: " + solrOriginalDocs.size() + "; But found:" + solrResponseDocs.size(),
+        solrOriginalDocs.size(), solrResponseDocs.size());
+    for (SolrDocument solrDoc : solrOriginalDocs) {
+      SolrInputDocument solrInputDoc = ClientUtils.toSolrInputDocument(solrDoc);
+      validateSolrDocContent(solrInputDoc, solrResponseDocs);
+    }
+  }
+
+  /**
+   * Function to query the collection and fetch the Solr docs
+   * @param collectionName -  Name of the collection
+   * @param solrQueryStr - Query string to be searched in Solr
+   * @param runAsAdmin - Boolean to specify whether to execute the Solr query as admin user
+   * @return -  Instance of SolrDocumentList
+   * @throws Exception
+   */
+  protected SolrDocumentList getSolrDocs(String collectionName,
+                                         String solrQueryStr,
+                                         boolean runAsAdmin) throws Exception {
+    String originalUser = getAuthenticatedUser();
+    try {
+      if (runAsAdmin == true) {
+        // Authenticate as user "admin"
+        setAuthenticationUser(ADMIN_USER);
+      }
+
+      CloudSolrServer cloudSolrServer = getCloudSolrServer(collectionName);
+      assertNotNull("Solr query shouldn't be null.", solrQueryStr);
+      SolrDocumentList solrDocs = null;
+      try {
+        SolrQuery query = new SolrQuery(solrQueryStr);
+        QueryResponse response = cloudSolrServer.query(query);
+        solrDocs = response.getResults();
+        return solrDocs;
+      } finally {
+        cloudSolrServer.shutdown();
+      }
+    } finally {
+      setAuthenticationUser(originalUser);
+    }
+  }
+
+  /**
+   * 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) {
+    for (SolrDocument solrRespDoc : solrRespDocs) {
+      String expFieldValue = (String) solrInputDoc.getFieldValue("id");
+      String resFieldValue = (String) solrRespDoc.getFieldValue("id");
+      if (expFieldValue.equals(resFieldValue)) {
+        int expectedRespFieldCount = solrRespDoc.size();
+        if (solrRespDoc.containsKey("_version_")) {
+          expectedRespFieldCount = expectedRespFieldCount - 1;
+        }
+        int expectedOrigFieldCount = solrInputDoc.size();
+        if (solrInputDoc.containsKey("_version_")) {
+          expectedOrigFieldCount = expectedOrigFieldCount - 1;
+        }
+        assertEquals("Expected " + expectedOrigFieldCount + " fields. But, found "
+              + expectedRespFieldCount + " fields", expectedOrigFieldCount , expectedRespFieldCount);
+        for (String field : solrInputDoc.getFieldNames()) {
+          if (field.equals("_version_") == true) {
+            continue;
+          }
+
+          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 {
+    verifyCollectionAdminOpPass(ADMIN_USER,
+                                CollectionAction.CREATE,
+                                collectionName);
+  }
+
+  /**
+   * Function to delete a solr collection with the name passed as parameter
+   * (Runs commands as ADMIN user)
+   * @param collectionName - Name of the collection
+   * This function will simply ignore the errors raised in deleting the collections.
+   * e.g: As part of the clean up job, the tests can issue a DELETE command on the collection which doesn't exist.
+   */
+  protected void deleteCollection(String collectionName) {
+    try {
+      verifyCollectionAdminOpPass(ADMIN_USER,
+                                  CollectionAction.DELETE,
+                                  collectionName);
+    } catch (Exception e) {
+      LOG.warn("Ignoring errors raised while deleting the collection : " + e.toString());
+    }
+  }
+
+  /**
+   * 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/22b6a348/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);
-  }
-}