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);
- }
-}