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/25 00:07:56 UTC
git commit: SENTRY-3: Create a diagnostics tool for configuration
validation (Prasad via Brock)
Repository: incubator-sentry
Updated Branches:
refs/heads/master cf798ac71 -> a4819f5b7
SENTRY-3: Create a diagnostics tool for configuration validation (Prasad via Brock)
Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/a4819f5b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/a4819f5b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/a4819f5b
Branch: refs/heads/master
Commit: a4819f5b7b8ce5fb9f3c9b94c6dbb1e2dfbe1f78
Parents: cf798ac
Author: Brock Noland <br...@apache.org>
Authored: Mon Feb 24 17:06:07 2014 -0600
Committer: Brock Noland <br...@apache.org>
Committed: Mon Feb 24 17:06:07 2014 -0600
----------------------------------------------------------------------
bin/config-tool.sh | 25 +
bin/sentry | 65 +++
.../binding/hive/HiveAuthzBindingHook.java | 12 +-
.../binding/hive/authz/HiveAuthzBinding.java | 9 +-
.../binding/hive/authz/SentryConfigTool.java | 510 +++++++++++++++++++
.../sentry/binding/hive/conf/HiveAuthzConf.java | 51 ++
sentry-core/sentry-core-common/pom.xml | 4 +
.../common/SentryConfigurationException.java | 67 +++
.../sentry/policy/common/PolicyEngine.java | 13 +-
.../sentry/policy/db/SimpleDBPolicyEngine.java | 37 +-
.../policy/search/SimpleSearchPolicyEngine.java | 22 +-
.../provider/common/AuthorizationProvider.java | 30 ++
.../common/NoAuthorizationProvider.java | 26 +
.../sentry/provider/common/ProviderBackend.java | 7 +
.../file/ResourceAuthorizationProvider.java | 57 ++-
.../file/SimpleFileProviderBackend.java | 79 ++-
.../provider/file/TestGetGroupMapping.java | 21 +
.../apache/sentry/tests/e2e/hive/Context.java | 6 +-
.../sentry/tests/e2e/hive/TestConfigTool.java | 304 +++++++++++
19 files changed, 1315 insertions(+), 30 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/bin/config-tool.sh
----------------------------------------------------------------------
diff --git a/bin/config-tool.sh b/bin/config-tool.sh
new file mode 100755
index 0000000..b286421
--- /dev/null
+++ b/bin/config-tool.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# 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.
+
+_CMD_JAR=sentry-binding-hive-*.jar
+_HIVE_CMD=${HIVE_HOME}/bin/hive
+for f in ${SENTRY_HOME}/lib/*.jar; do
+ HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:${f}
+done
+
+${_HIVE_CMD} --service jar ${SENTRY_HOME}/lib/${_CMD_JAR} org.apache.sentry.binding.hive.authz.SentryConfigTool "$@"
+
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/bin/sentry
----------------------------------------------------------------------
diff --git a/bin/sentry b/bin/sentry
new file mode 100755
index 0000000..9f2ce77
--- /dev/null
+++ b/bin/sentry
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+# 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.
+
+bin=`dirname "$0"`
+myhome=`cd "$bin/.."; pwd`
+
+# the root of the Hive installation
+if [[ -z $SENTRY_HOME ]] ; then
+ export SENTRY_HOME=$myhome
+fi
+
+_HIVE_CMD=hive
+#check to see if the hive conf dir is given as an optional argument
+while [ $# -gt 0 ]; do # Until you run out of parameters . . .
+ case "$1" in
+ --hive-config)
+ shift
+ confdir=$1
+ shift
+ export HIVE_CONF_DIR=$confdir
+ echo Using hive-conf-dir $HIVE_CONF_DIR
+ ;;
+ --hive-home)
+ shift
+ homedir=$1
+ shift
+ export HIVE_HOME=$homedir
+ echo Using hive-home $HIVE_HOME
+ ;;
+ --command)
+ shift
+ case "$1" in
+ config-tool)
+ shift
+ $SENTRY_HOME/bin/config-tool.sh "$@"
+ ;;
+ *)
+ echo Unknown option $1
+ echo "Usage sentry --command <config-tool [config-tool-options]>"
+ break
+ ;;
+ esac
+ break
+ ;;
+ *)
+ echo "Usage sentry --command <config-tool [config-tool-options]>"
+ break
+ ;;
+ esac
+done
+
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 cac4864..3624e8f 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
@@ -277,7 +277,17 @@ implements HiveDriverFilterHook {
authorizeWithHiveBindings(context, stmtAuthObject, stmtOperation);
} catch (AuthorizationException e) {
executeOnFailureHooks(context, stmtOperation, e);
- throw new SemanticException("No valid privileges", e);
+ String permsRequired = "";
+ for (String perm : hiveAuthzBinding.getLastQueryPermissionErrors()) {
+ permsRequired += perm + ";";
+ }
+ context.getConf().set(HiveAuthzConf.HIVE_SENTRY_AUTH_ERRORS, permsRequired);
+ throw new SemanticException(HiveAuthzConf.HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE, e);
+ }
+ if ("true".equalsIgnoreCase(context.getConf().
+ get(HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION))) {
+ throw new SemanticException(HiveAuthzConf.HIVE_SENTRY_MOCK_ERROR + " Mock query compilation aborted. Set " +
+ HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION + " to 'false' for normal query processing");
}
hiveAuthzBinding.set(context.getConf());
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzBinding.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzBinding.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzBinding.java
index 45d5d3b..f6a1ecc 100644
--- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzBinding.java
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzBinding.java
@@ -63,7 +63,7 @@ public class HiveAuthzBinding {
public HiveAuthzBinding (HiveConf hiveConf, HiveAuthzConf authzConf) throws Exception {
this.authzConf = authzConf;
this.authServer = new Server(authzConf.get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
- this.authProvider = getAuthProvider(hiveConf, authServer.getName());
+ this.authProvider = getAuthProvider(hiveConf, authzConf, authServer.getName());
}
/**
@@ -102,7 +102,8 @@ public class HiveAuthzBinding {
}
// Instantiate the configured authz provider
- private AuthorizationProvider getAuthProvider(HiveConf hiveConf, String serverName) throws Exception {
+ public static AuthorizationProvider getAuthProvider(HiveConf hiveConf, HiveAuthzConf authzConf,
+ String serverName) throws Exception {
boolean isTestingMode = Boolean.parseBoolean(Strings.nullToEmpty(
authzConf.get(AuthzConfVars.SENTRY_TESTING_MODE.getVar())).trim());
LOG.debug("Testing mode is " + isTestingMode);
@@ -232,4 +233,8 @@ public class HiveAuthzBinding {
private AuthorizableType getAuthzType (List<DBModelAuthorizable> hierarchy){
return hierarchy.get(hierarchy.size() -1).getAuthzType();
}
+
+ public List<String> getLastQueryPermissionErrors() {
+ return authProvider.getLastFailedPermissions();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryConfigTool.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryConfigTool.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryConfigTool.java
new file mode 100644
index 0000000..d7a518d
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/SentryConfigTool.java
@@ -0,0 +1,510 @@
+/*
+ * 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.binding.hive.authz;
+
+import java.security.CodeSource;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Set;
+
+import org.apache.sentry.binding.hive.HiveAuthzBindingSessionHook;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
+import org.apache.hadoop.hive.ql.Driver;
+import org.apache.hadoop.hive.ql.parse.SemanticException;
+import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse;
+import org.apache.hadoop.hive.ql.session.SessionState;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.sentry.binding.hive.HiveAuthzBindingHook;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
+import org.apache.sentry.provider.common.AuthorizationProvider;
+import org.apache.sentry.core.common.SentryConfigurationException;
+import org.apache.sentry.core.model.db.Server;
+import org.apache.sentry.core.common.Subject;
+
+public class SentryConfigTool {
+ private String sentrySiteFile = null;
+ private String policyFile = null;
+ private String query = null;
+ private String jdbcURL = null;
+ private String user = null;
+ private String passWord = null;
+ private boolean listPerms = false;
+ private boolean validate = false;
+ private HiveConf hiveConf = null;
+ private HiveAuthzConf authzConf = null;
+ private AuthorizationProvider sentryProvider = null;
+
+ public SentryConfigTool() {
+
+ }
+
+ public AuthorizationProvider getSentryProvider() {
+ return sentryProvider;
+ }
+
+ public void setSentryProvider(AuthorizationProvider sentryProvider) {
+ this.sentryProvider = sentryProvider;
+ }
+
+ public HiveConf getHiveConf() {
+ return hiveConf;
+ }
+
+ public void setHiveConf(HiveConf hiveConf) {
+ this.hiveConf = hiveConf;
+ }
+
+ public HiveAuthzConf getAuthzConf() {
+ return authzConf;
+ }
+
+ public void setAuthzConf(HiveAuthzConf authzConf) {
+ this.authzConf = authzConf;
+ }
+
+ public boolean isValidate() {
+ return validate;
+ }
+
+ public void setValidate(boolean validate) {
+ this.validate = validate;
+ }
+
+ public String getSentrySiteFile() {
+ return sentrySiteFile;
+ }
+
+ public void setSentrySiteFile(String sentrySiteFile) {
+ this.sentrySiteFile = sentrySiteFile;
+ }
+
+ public String getPolicyFile() {
+ return policyFile;
+ }
+
+ public void setPolicyFile(String policyFile) {
+ this.policyFile = policyFile;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ public String getJdbcURL() {
+ return jdbcURL;
+ }
+
+ public void setJdbcURL(String jdbcURL) {
+ this.jdbcURL = jdbcURL;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getPassWord() {
+ return passWord;
+ }
+
+ public void setPassWord(String passWord) {
+ this.passWord = passWord;
+ }
+
+ public boolean isListPerms() {
+ return listPerms;
+ }
+
+ public void setListPerms(boolean listPerms) {
+ this.listPerms = listPerms;
+ }
+
+ /**
+ * set the required system property to be read by HiveConf and AuthzConf
+ * @throws Exception
+ */
+ public void setupConfig() throws Exception {
+ System.out.println("Configuration: ");
+ CodeSource src = SentryConfigTool.class.getProtectionDomain()
+ .getCodeSource();
+ if (src != null) {
+ System.out.println("Sentry package jar: " + src.getLocation());
+ }
+
+ if (getPolicyFile() != null) {
+ System.setProperty(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar(),
+ getPolicyFile());
+ }
+ System.setProperty(AuthzConfVars.SENTRY_TESTING_MODE.getVar(), "true");
+ setHiveConf(new HiveConf(SessionState.class));
+ getHiveConf().setVar(ConfVars.SEMANTIC_ANALYZER_HOOK,
+ HiveAuthzBindingHook.class.getName());
+ try {
+ System.out.println("Hive config: " + getHiveConf().getHiveSiteLocation());
+ } catch (NullPointerException e) {
+ // Hack, hiveConf doesn't provide a reliable way check if it found a valid
+ // hive-site
+ throw new SentryConfigurationException("Didn't find a hive-site.xml");
+
+ }
+
+ if (getSentrySiteFile() != null) {
+ getHiveConf()
+ .set(HiveAuthzConf.HIVE_SENTRY_CONF_URL, getSentrySiteFile());
+ }
+
+ setAuthzConf(HiveAuthzConf.getAuthzConf(getHiveConf()));
+ System.out.println("Sentry config: "
+ + getAuthzConf().getHiveAuthzSiteFile());
+ System.out.println("Sentry Policy: "
+ + getAuthzConf().get(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar()));
+ System.out.println("Sentry server: "
+ + getAuthzConf().get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
+
+ setSentryProvider(getAuthorizationProvider());
+ }
+
+ // load auth provider
+ private AuthorizationProvider getAuthorizationProvider()
+ throws IllegalStateException, SentryConfigurationException {
+ String serverName = new Server(getAuthzConf().get(
+ AuthzConfVars.AUTHZ_SERVER_NAME.getVar())).getName();
+ // get the configured sentry provider
+ AuthorizationProvider sentryProvider = null;
+ try {
+ sentryProvider = HiveAuthzBinding.getAuthProvider(getHiveConf(),
+ authzConf, serverName);
+ } catch (SentryConfigurationException eC) {
+ printConfigErrors(eC);
+ } catch (Exception e) {
+ throw new IllegalStateException("Couldn't load sentry provider ", e);
+ }
+ return sentryProvider;
+ }
+
+ // validate policy files
+ public void validatePolicy() throws Exception {
+ try {
+ getSentryProvider().validateResource(true);
+ } catch (SentryConfigurationException e) {
+ printConfigErrors(e);
+ }
+ System.out.println("No errors found in the policy file");
+ }
+
+ // list permissions for given user
+ public void listPerms() throws Exception {
+ getSentryProvider().validateResource(true);
+ System.out.println("Available privileges for user " + getUser() + ":");
+ Set<String> permList = getSentryProvider().listPermissionsForSubject(
+ new Subject(getUser()));
+ for (String perms : permList) {
+ System.out.println("\t" + perms);
+ }
+ if (permList.isEmpty()) {
+ System.out.println("\t*** No permissions available ***");
+ }
+ }
+
+ // Verify the given query
+ public void verifyLocalQuery(String queryStr) throws Exception {
+ // setup Hive driver
+ SessionState session = new SessionState(getHiveConf());
+ SessionState.start(session);
+ Driver driver = new Driver(session.getConf(), getUser(), null);
+
+ // compile the query
+ CommandProcessorResponse compilerStatus = driver
+ .compileAndRespond(queryStr);
+ if (compilerStatus.getResponseCode() != 0) {
+ String errMsg = compilerStatus.getErrorMessage();
+ if (errMsg.contains(HiveAuthzConf.HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE)) {
+ printMissingPerms(getHiveConf().get(
+ HiveAuthzConf.HIVE_SENTRY_AUTH_ERRORS));
+ }
+ throw new SemanticException("Compilation error: "
+ + compilerStatus.getErrorMessage());
+ }
+ driver.close();
+ System.out
+ .println("User " + getUser() + " has privileges to run the query");
+ }
+
+ // connect to remote HS2 and run mock query
+ public void verifyRemoteQuery(String queryStr) throws Exception {
+ Class.forName("org.apache.hive.jdbc.HiveDriver");
+ Connection conn = DriverManager.getConnection(getJdbcURL(), getUser(),
+ getPassWord());
+ Statement stmt = conn.createStatement();
+ if (!isSentryEnabledOnHiveServer(stmt)) {
+ throw new IllegalStateException("Sentry is not enabled on HiveServer2");
+ }
+ stmt.execute("set " + HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION + "=true");
+ try {
+ stmt.execute(queryStr);
+ } catch (SQLException e) {
+ String errMsg = e.getMessage();
+ if (errMsg.contains(HiveAuthzConf.HIVE_SENTRY_MOCK_ERROR)) {
+ System.out.println("User "
+ + readConfig(stmt, HiveAuthzConf.HIVE_SENTRY_SUBJECT_NAME)
+ + " has privileges to run the query");
+ return;
+ } else if (errMsg
+ .contains(HiveAuthzConf.HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE)) {
+ printMissingPerms(readConfig(stmt,
+ HiveAuthzConf.HIVE_SENTRY_AUTH_ERRORS));
+ throw e;
+ } else {
+ throw e;
+ }
+ } finally {
+ if (!stmt.isClosed()) {
+ stmt.close();
+ }
+ conn.close();
+ }
+
+ }
+
+ // verify senty session hook is set
+ private boolean isSentryEnabledOnHiveServer(Statement stmt)
+ throws SQLException {
+ return HiveAuthzBindingSessionHook.class.getName().equalsIgnoreCase(
+ readConfig(stmt, HiveConf.ConfVars.HIVE_SERVER2_SESSION_HOOK.varname));
+ }
+
+ // read a config value using 'set' statement
+ private String readConfig(Statement stmt, String configKey)
+ throws SQLException {
+ ResultSet res = stmt.executeQuery("set " + configKey);
+ if (!res.next()) {
+ return null;
+ }
+ // parse key=value result format
+ String result = res.getString(1);
+ res.close();
+ return result.substring(result.indexOf("=") + 1);
+ }
+
+ // print configuration/policy file errors and warnings
+ private void printConfigErrors(SentryConfigurationException configException)
+ throws SentryConfigurationException {
+ System.out.println(" *** Found configuration problems *** ");
+ for (String errMsg : configException.getConfigErrors()) {
+ System.out.println("ERROR: " + errMsg);
+ }
+ for (String warnMsg : configException.getConfigWarnings()) {
+ System.out.println("Warning: " + warnMsg);
+ }
+ throw configException;
+ }
+
+ // extract the authorization errors from config property and print
+ private void printMissingPerms(String errMsg) {
+ if (errMsg == null || errMsg.isEmpty()) {
+ return;
+ }
+ System.out.println("*** Query compilation failed ***");
+ String perms[] = errMsg.replaceFirst(
+ ".*" + HiveAuthzConf.HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE, "")
+ .split(";");
+ System.out.println("Required privileges for given query:");
+ for (int count = 0; count < perms.length; count++) {
+ System.out.println(" \t " + perms[count]);
+ }
+ }
+
+ // print usage
+ private void usage(Options sentryOptions) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("Sentry", sentryOptions);
+ System.exit(-1);
+ }
+
+ /**
+ * parse arguments
+ *
+ * -d,--debug enable debug output
+ * -e,--query <arg> Query privilege verification, requires -u
+ * -h,--help Print usage
+ * -i,--policyIni <arg> Policy file path
+ * -j,--jdbcURL <arg> JDBC URL
+ * -l,--listPerms list permissions for given user, requires -u
+ * -p,--password <arg> Password
+ * -s,--sentry-site <arg> sentry-site file path
+ * -u,--user <arg> user name
+ * -v,--validate Validate policy file
+ * @param args
+ */
+ private void parseArgs(String[] args) {
+ boolean enableDebug = false;
+
+ Options sentryOptions = new Options();
+
+ Option helpOpt = new Option("h", "help", false, "Print usage");
+ helpOpt.setRequired(false);
+
+ Option validateOpt = new Option("v", "validate", false,
+ "Validate policy file");
+ validateOpt.setRequired(false);
+
+ Option queryOpt = new Option("e", "query", true,
+ "Query privilege verification, requires -u");
+ queryOpt.setRequired(false);
+
+ Option listPermsOpt = new Option("l", "listPerms", false,
+ "list permissions for given user, requires -u");
+ listPermsOpt.setRequired(false);
+
+ // required args
+ OptionGroup sentryOptGroup = new OptionGroup();
+ sentryOptGroup.addOption(helpOpt);
+ sentryOptGroup.addOption(validateOpt);
+ sentryOptGroup.addOption(queryOpt);
+ sentryOptGroup.addOption(listPermsOpt);
+ sentryOptGroup.setRequired(true);
+ sentryOptions.addOptionGroup(sentryOptGroup);
+
+ // optional args
+ Option jdbcArg = new Option("j", "jdbcURL", true, "JDBC URL");
+ jdbcArg.setRequired(false);
+ sentryOptions.addOption(jdbcArg);
+
+ Option sentrySitePath = new Option("s", "sentry-site", true,
+ "sentry-site file path");
+ sentrySitePath.setRequired(false);
+ sentryOptions.addOption(sentrySitePath);
+
+ Option globalPolicyPath = new Option("i", "policyIni", true,
+ "Policy file path");
+ globalPolicyPath.setRequired(false);
+ sentryOptions.addOption(globalPolicyPath);
+
+ Option userOpt = new Option("u", "user", true, "user name");
+ userOpt.setRequired(false);
+ sentryOptions.addOption(userOpt);
+
+ Option passWordOpt = new Option("p", "password", true, "Password");
+ userOpt.setRequired(false);
+ sentryOptions.addOption(passWordOpt);
+
+ Option debugOpt = new Option("d", "debug", false, "enable debug output");
+ debugOpt.setRequired(false);
+ sentryOptions.addOption(debugOpt);
+
+ try {
+ Parser parser = new GnuParser();
+ CommandLine cmd = parser.parse(sentryOptions, args);
+
+ for (Option opt : cmd.getOptions()) {
+ if (opt.getOpt().equals("s")) {
+ setSentrySiteFile(opt.getValue());
+ } else if (opt.getOpt().equals("i")) {
+ setPolicyFile(opt.getValue());
+ } else if (opt.getOpt().equals("e")) {
+ setQuery(opt.getValue());
+ } else if (opt.getOpt().equals("j")) {
+ setJdbcURL(opt.getValue());
+ } else if (opt.getOpt().equals("u")) {
+ setUser(opt.getValue());
+ } else if (opt.getOpt().equals("p")) {
+ setPassWord(opt.getValue());
+ } else if (opt.getOpt().equals("l")) {
+ setListPerms(true);
+ } else if (opt.getOpt().equals("v")) {
+ setValidate(true);
+ } else if (opt.getOpt().equals("h")) {
+ usage(sentryOptions);
+ } else if (opt.getOpt().equals("d")) {
+ enableDebug = true;
+ }
+ }
+
+ if (isListPerms() && (getUser() == null)) {
+ throw new ParseException("Can't use -l without -u ");
+ }
+ if ((getQuery() != null) && (getUser() == null)) {
+ throw new ParseException("Must use -u with -e ");
+ }
+ } catch (ParseException e1) {
+ System.out.println("Argument parsing error: " + e1.getMessage());
+ usage(sentryOptions);
+ }
+
+ if (!enableDebug) {
+ // turn off log
+ LogManager.getRootLogger().setLevel(Level.OFF);
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ SentryConfigTool sentryTool = new SentryConfigTool();
+
+ try {
+ // parse arguments
+ sentryTool.parseArgs(args);
+
+ // load configuration
+ sentryTool.setupConfig();
+
+ // validate configuration
+ if (sentryTool.isValidate()) {
+ sentryTool.validatePolicy();
+ }
+
+ // list permissions for give user
+ if (sentryTool.isListPerms()) {
+ sentryTool.listPerms();
+ }
+
+ // verify given query
+ if (sentryTool.getQuery() != null) {
+ if (sentryTool.getJdbcURL() != null) {
+ sentryTool.verifyRemoteQuery(sentryTool.getQuery());
+ } else {
+ sentryTool.verifyLocalQuery(sentryTool.getQuery());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Sentry tool reported Errors: " + e.getMessage());
+ System.exit(1);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 b7d79d6..c4f12b5 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
@@ -16,12 +16,14 @@
*/
package org.apache.sentry.binding.hive.conf;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.conf.HiveConf;
import org.mortbay.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +38,10 @@ public class HiveAuthzConf extends Configuration {
public static final String HIVE_SENTRY_CONF_URL = "hive.sentry.conf.url";
public static final String HIVE_ACCESS_SUBJECT_NAME = "hive.access.subject.name";
public static final String HIVE_SENTRY_SUBJECT_NAME = "hive.sentry.subject.name";
+ public static final String HIVE_SENTRY_AUTH_ERRORS = "sentry.hive.authorization.errors";
+ public static final String HIVE_SENTRY_MOCK_COMPILATION = "hive.sentry.mock.compilation";
+ public static final String HIVE_SENTRY_MOCK_ERROR = "hive.sentry.mock.error";
+ public static final String HIVE_SENTRY_PRIVILEGE_ERROR_MESSAGE = "No valid privileges";
/**
* Config setting definitions
@@ -132,11 +138,13 @@ public class HiveAuthzConf extends Configuration {
private static final Logger LOG = LoggerFactory
.getLogger(HiveAuthzConf.class);
public static final String AUTHZ_SITE_FILE = "sentry-site.xml";
+ private final String hiveAuthzSiteFile;
public HiveAuthzConf(URL hiveAuthzSiteURL) {
super(false);
addResource(hiveAuthzSiteURL);
applySystemProperties();
+ this.hiveAuthzSiteFile = hiveAuthzSiteURL.toString();
}
/**
* Apply system properties to this object if the property name is defined in ConfVars
@@ -182,4 +190,47 @@ public class HiveAuthzConf extends Configuration {
}
return retVal;
}
+
+ public String getHiveAuthzSiteFile() {
+ return hiveAuthzSiteFile;
+ }
+
+ /**
+ * Extract the authz config file path from given hive conf and load the authz config
+ * @param hiveConf
+ * @return
+ * @throws IllegalArgumentException
+ */
+ public static HiveAuthzConf getAuthzConf(HiveConf hiveConf)
+ throws IllegalArgumentException {
+ boolean depreicatedConfigFile = false;
+
+ String hiveAuthzConf = hiveConf.get(HiveAuthzConf.HIVE_SENTRY_CONF_URL);
+ if (hiveAuthzConf == null
+ || (hiveAuthzConf = hiveAuthzConf.trim()).isEmpty()) {
+ hiveAuthzConf = hiveConf.get(HiveAuthzConf.HIVE_ACCESS_CONF_URL);
+ depreicatedConfigFile = true;
+ }
+
+ if (hiveAuthzConf == null
+ || (hiveAuthzConf = hiveAuthzConf.trim()).isEmpty()) {
+ throw new IllegalArgumentException("Configuration key "
+ + HiveAuthzConf.HIVE_SENTRY_CONF_URL + " value '" + hiveAuthzConf
+ + "' is invalid.");
+ }
+
+ try {
+ return new HiveAuthzConf(new URL(hiveAuthzConf));
+ } catch (MalformedURLException e) {
+ if (depreicatedConfigFile) {
+ throw new IllegalArgumentException("Configuration key "
+ + HiveAuthzConf.HIVE_ACCESS_CONF_URL
+ + " specifies a malformed URL '" + hiveAuthzConf + "'", e);
+ } else {
+ throw new IllegalArgumentException("Configuration key "
+ + HiveAuthzConf.HIVE_SENTRY_CONF_URL
+ + " specifies a malformed URL '" + hiveAuthzConf + "'", e);
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 a14f129..d50963e 100644
--- a/sentry-core/sentry-core-common/pom.xml
+++ b/sentry-core/sentry-core-common/pom.xml
@@ -33,6 +33,10 @@ limitations under the License.
<artifactId>guava</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/SentryConfigurationException.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/SentryConfigurationException.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/SentryConfigurationException.java
new file mode 100644
index 0000000..516b2da
--- /dev/null
+++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/SentryConfigurationException.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.shiro.config.ConfigurationException;
+
+public class SentryConfigurationException extends ConfigurationException {
+ private List<String> configErrors = new ArrayList<String>();
+ private List<String> configWarnings = new ArrayList<String>();
+
+ public boolean hasWarnings() {
+ return !configWarnings.isEmpty();
+ }
+
+ public boolean hasErrors() {
+ return !configErrors.isEmpty();
+ }
+
+ public SentryConfigurationException() {
+ super();
+ }
+
+ public SentryConfigurationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SentryConfigurationException(String message) {
+ super(message);
+ }
+
+ public SentryConfigurationException(Throwable cause) {
+ super(cause);
+ }
+
+ public List<String> getConfigErrors() {
+ return configErrors;
+ }
+
+ public void setConfigErrors(List<String> configErrors) {
+ this.configErrors = configErrors;
+ }
+
+ public List<String> getConfigWarnings() {
+ return configWarnings;
+ }
+
+ public void setConfigWarnings(List<String> configWarnings) {
+ this.configWarnings = configWarnings;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/PolicyEngine.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/PolicyEngine.java b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/PolicyEngine.java
index 693de1b..c08d082 100644
--- a/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/PolicyEngine.java
+++ b/sentry-policy/sentry-policy-common/src/main/java/org/apache/sentry/policy/common/PolicyEngine.java
@@ -20,7 +20,9 @@ package org.apache.sentry.policy.common;
import java.util.List;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
public interface PolicyEngine {
@@ -41,6 +43,15 @@ public interface PolicyEngine {
* @param group name
* @return non-null immutable set of permissions
*/
- public ImmutableSetMultimap<String, String> getPermissions(List<? extends Authorizable> authorizables, List<String> groups);
+ public ImmutableSetMultimap<String, String> getPermissions(
+ List<? extends Authorizable> authorizables, List<String> groups)
+ throws SentryConfigurationException;
+ public ImmutableSet<String> listPermissions(String groupName)
+ throws SentryConfigurationException;
+
+ public ImmutableSet<String> listPermissions(List<String> groupName)
+ throws SentryConfigurationException;
+
+ public void validatePolicy(boolean strictValidation) throws SentryConfigurationException;
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/SimpleDBPolicyEngine.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/SimpleDBPolicyEngine.java b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/SimpleDBPolicyEngine.java
index 1d72f87..1d01b47 100644
--- a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/SimpleDBPolicyEngine.java
+++ b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/SimpleDBPolicyEngine.java
@@ -19,11 +19,14 @@ package org.apache.sentry.policy.db;
import javax.annotation.Nullable;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
+
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.core.model.db.AccessURI;
import org.apache.sentry.core.model.db.Database;
import org.apache.sentry.policy.common.PermissionFactory;
@@ -36,7 +39,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
-
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -50,13 +52,15 @@ public class SimpleDBPolicyEngine implements PolicyEngine {
public final static String ACCESS_ALLOW_URI_PER_DB_POLICYFILE = "sentry.allow.uri.db.policyfile";
private ProviderBackend providerBackend;
+ private String serverName;
+ private List<? extends RoleValidator> validators;
public SimpleDBPolicyEngine(String serverName, ProviderBackend providerBackend) {
- List<? extends RoleValidator> validators =
- Lists.newArrayList(new ServersAllIsInvalid(), new DatabaseMustMatch(),
- new DatabaseRequiredInRole(), new ServerNameMustMatch(serverName));
+ validators = Lists.newArrayList(new ServersAllIsInvalid(), new DatabaseMustMatch(),
+ new DatabaseRequiredInRole(), new ServerNameMustMatch(serverName));
this.providerBackend = providerBackend;
this.providerBackend.process(validators);
+ this.serverName = serverName;
}
/**
@@ -71,7 +75,9 @@ public class SimpleDBPolicyEngine implements PolicyEngine {
* {@inheritDoc}
*/
@Override
- public ImmutableSetMultimap<String, String> getPermissions(List<? extends Authorizable> authorizables, List<String> groups) {
+ public ImmutableSetMultimap<String, String> getPermissions(
+ List<? extends Authorizable> authorizables, List<String> groups)
+ throws SentryConfigurationException {
String database = null;
Boolean isURI = false;
for(Authorizable authorizable : authorizables) {
@@ -139,4 +145,25 @@ public class SimpleDBPolicyEngine implements PolicyEngine {
}
return result;
}
+
+ @Override
+ public void validatePolicy(boolean strictValidation) throws SentryConfigurationException {
+ this.providerBackend.validatePolicy(validators, strictValidation);
+ }
+
+ @Override
+ public ImmutableSet<String> listPermissions(String groupName) throws SentryConfigurationException {
+ return getDBRoles(Database.ALL.getName(), groupName, true, providerBackend.getRoles());
+ }
+
+ @Override
+ public ImmutableSet<String> listPermissions(List<String> groupNames)
+ throws SentryConfigurationException {
+ ImmutableSet.Builder<String> resultBuilder = ImmutableSet.builder();
+ for (String groupName : groupNames) {
+ resultBuilder.addAll(listPermissions(groupName));
+ }
+ return resultBuilder.build();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
----------------------------------------------------------------------
diff --git a/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java b/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
index 21711ef..51ab35d 100644
--- a/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
+++ b/sentry-policy/sentry-policy-search/src/main/java/org/apache/sentry/policy/search/SimpleSearchPolicyEngine.java
@@ -21,8 +21,10 @@ import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
+
import org.apache.shiro.config.ConfigurationException;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.policy.common.PermissionFactory;
import org.apache.sentry.policy.common.PolicyEngine;
import org.apache.sentry.policy.common.RoleValidator;
@@ -33,7 +35,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
-
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -111,4 +112,23 @@ public class SimpleSearchPolicyEngine implements PolicyEngine {
}
return result;
}
+
+ @Override
+ public ImmutableSet<String> listPermissions(String groupName)
+ throws SentryConfigurationException {
+ // TODO: not supported yet
+ throw new SentryConfigurationException("Not implemented yet");
+ }
+
+ @Override
+ public ImmutableSet<String> listPermissions(List<String> groupName)
+ throws SentryConfigurationException {
+ throw new SentryConfigurationException("Not implemented yet");
+ }
+
+ @Override
+ public void validatePolicy(boolean strictValidation)
+ throws SentryConfigurationException {
+ throw new SentryConfigurationException("Not implemented yet");
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 1244755..4887678 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
@@ -21,6 +21,7 @@ import java.util.Set;
import org.apache.sentry.core.common.Action;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.core.common.Subject;
public interface AuthorizationProvider {
@@ -44,4 +45,33 @@ public interface AuthorizationProvider {
* @return GroupMappingService used by the AuthorizationProvider
*/
public GroupMappingService getGroupMapping();
+
+ /***
+ * Validate the policy file format for syntax and semantic errors
+ * @param strictValidation
+ * @throws SentryConfigurationException
+ */
+ public void validateResource(boolean strictValidation) throws SentryConfigurationException;
+
+ /***
+ * Returns the list privileges for the given subject
+ * @param subject
+ * @return
+ * @throws SentryConfigurationException
+ */
+ public Set<String> listPermissionsForSubject(Subject subject) throws SentryConfigurationException;
+
+ /**
+ * Returns the list privileges for the given group
+ * @param groupName
+ * @return
+ * @throws SentryConfigurationException
+ */
+ public Set<String> listPermissionsForGroup(String groupName) throws SentryConfigurationException;
+
+ /***
+ * Returns the list of missing privileges of the last access request
+ * @return
+ */
+ public List<String> getLastFailedPermissions();
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 f48eafe..8f18926 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
@@ -16,11 +16,14 @@
*/
package org.apache.sentry.provider.common;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.sentry.core.common.Action;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.core.common.Subject;
public class NoAuthorizationProvider implements AuthorizationProvider {
@@ -36,4 +39,27 @@ public class NoAuthorizationProvider implements AuthorizationProvider {
public GroupMappingService getGroupMapping() {
return noGroupMappingService;
}
+
+ @Override
+ public void validateResource(boolean strictValidation) throws SentryConfigurationException {
+ return;
+ }
+
+ @Override
+ public Set<String> listPermissionsForSubject(Subject subject)
+ throws SentryConfigurationException {
+ return new HashSet<String>();
+ }
+
+ @Override
+ public Set<String> listPermissionsForGroup(String groupName)
+ throws SentryConfigurationException {
+ return new HashSet<String>();
+ }
+
+ @Override
+ public List<String> getLastFailedPermissions() {
+ return new ArrayList<String>();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/ProviderBackend.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/ProviderBackend.java b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/ProviderBackend.java
index 415a509..327a3a5 100644
--- a/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/ProviderBackend.java
+++ b/sentry-provider/sentry-provider-common/src/main/java/org/apache/sentry/provider/common/ProviderBackend.java
@@ -17,8 +17,12 @@
package org.apache.sentry.provider.common;
import javax.annotation.Nullable;
+
import java.util.List;
+
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.policy.common.RoleValidator;
+
import com.google.common.collect.ImmutableSet;
/**
@@ -36,4 +40,7 @@ public interface ProviderBackend {
* least once prior.
*/
public Roles getRoles();
+
+ public void validatePolicy(List<? extends RoleValidator> validators, boolean strictValidation)
+ throws SentryConfigurationException;
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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 205d012..0743604 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
@@ -21,11 +21,13 @@ import static org.apache.sentry.provider.file.PolicyFileConstants.KV_JOINER;
import static org.apache.sentry.provider.file.PolicyFileConstants.PRIVILEGE_NAME;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import org.apache.sentry.core.common.Action;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.core.common.Subject;
import org.apache.sentry.policy.common.PermissionFactory;
import org.apache.sentry.policy.common.PolicyEngine;
@@ -46,6 +48,7 @@ public abstract class ResourceAuthorizationProvider implements AuthorizationProv
private final GroupMappingService groupService;
private final PolicyEngine policy;
private final PermissionFactory permissionFactory;
+ private final List<String> lastFailedPermissions = new ArrayList<String>();
public ResourceAuthorizationProvider(PolicyEngine policy,
GroupMappingService groupService) {
@@ -80,16 +83,16 @@ public abstract class ResourceAuthorizationProvider implements AuthorizationProv
private boolean doHasAccess(Subject subject,
List<? extends Authorizable> authorizables, Set<? extends Action> actions) {
- List<String> groups = groupService.getGroups(subject.getName());
+ List<String> groups = getGroups(subject);
List<String> hierarchy = new ArrayList<String>();
for (Authorizable authorizable : authorizables) {
hierarchy.add(KV_JOINER.join(authorizable.getTypeName(), authorizable.getName()));
}
Iterable<Permission> permissions = getPermissions(authorizables, groups);
- for (Action action : actions) {
- String requestPermission = AUTHORIZABLE_JOINER.join(hierarchy);
- requestPermission = AUTHORIZABLE_JOINER.join(requestPermission,
- KV_JOINER.join(PRIVILEGE_NAME, action.getValue()));
+ List<String> requestPermissions = buildPermissions(authorizables, actions);
+ lastFailedPermissions.clear();
+
+ for (String requestPermission : requestPermissions) {
for (Permission permission : permissions) {
/*
* Does the permission granted in the policy file imply the requested action?
@@ -104,6 +107,7 @@ public abstract class ResourceAuthorizationProvider implements AuthorizationProv
}
}
}
+ lastFailedPermissions.addAll(requestPermissions);
return false;
}
@@ -121,4 +125,47 @@ public abstract class ResourceAuthorizationProvider implements AuthorizationProv
public GroupMappingService getGroupMapping() {
return groupService;
}
+
+ private List<String> getGroups(Subject subject) {
+ return groupService.getGroups(subject.getName());
+ }
+
+ @Override
+ public void validateResource(boolean strictValidation) throws SentryConfigurationException {
+ policy.validatePolicy(strictValidation);
+ }
+
+ @Override
+ public Set<String> listPermissionsForSubject(Subject subject) throws SentryConfigurationException {
+ return policy.listPermissions(getGroups(subject));
+ }
+
+ @Override
+ public Set<String> listPermissionsForGroup(String groupName) throws SentryConfigurationException {
+ return policy.listPermissions(groupName);
+ }
+
+ @Override
+ public List<String> getLastFailedPermissions() {
+ return lastFailedPermissions;
+ }
+
+ private List<String> buildPermissions(List<? extends Authorizable> authorizables,
+ Set<? extends Action> actions) {
+ List<String> hierarchy = new ArrayList<String>();
+ List<String> requestedPermissions = new ArrayList<String>();
+
+ for (Authorizable authorizable : authorizables) {
+ hierarchy.add(KV_JOINER.join(authorizable.getTypeName(), authorizable.getName()));
+ }
+
+ for (Action action : actions) {
+ String requestPermission = AUTHORIZABLE_JOINER.join(hierarchy);
+ requestPermission = AUTHORIZABLE_JOINER.join(requestPermission,
+ KV_JOINER.join(PRIVILEGE_NAME, action.getValue()));
+ requestedPermissions.add(requestPermission);
+ }
+ return requestedPermissions;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java
index f432915..9eabb53 100644
--- a/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java
+++ b/sentry-provider/sentry-provider-file/src/main/java/org/apache/sentry/provider/file/SimpleFileProviderBackend.java
@@ -25,6 +25,7 @@ import static org.apache.sentry.provider.file.PolicyFileConstants.USERS;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -36,6 +37,7 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.SentryConfigurationException;
import org.apache.sentry.policy.common.RoleValidator;
import org.apache.sentry.provider.common.ProviderBackend;
import org.apache.sentry.provider.common.Roles;
@@ -70,6 +72,8 @@ public class SimpleFileProviderBackend implements ProviderBackend {
private Roles rolesStorage;
private final Configuration conf;
private boolean processed;
+ private final List<String> configErrors = new ArrayList<String>();
+ private final List<String> configWarnings = new ArrayList<String>();
public SimpleFileProviderBackend(String resourcePath) throws IOException {
this(new Configuration(), resourcePath);
@@ -92,11 +96,26 @@ public class SimpleFileProviderBackend implements ProviderBackend {
* {@inheritDoc}
*/
public void process(List<? extends RoleValidator> validators) {
+ configErrors.clear();
+ perDbResources.clear();
+ Ini ini;
+
LOGGER.info("Parsing " + resourcePath);
Roles roles = new Roles();
try {
perDbResources.clear();
- Ini ini = PolicyFiles.loadFromPath(fileSystem, resourcePath);
+ try {
+ ini = PolicyFiles.loadFromPath(fileSystem, resourcePath);
+ } catch (IOException e) {
+ configErrors.add("Failed to read policy file " + resourcePath +
+ " Error: " + e.getMessage());
+ throw new SentryConfigurationException("Error loading policy file " + resourcePath, e);
+ } catch (IllegalArgumentException e) {
+ configErrors.add("Failed to read policy file " + resourcePath +
+ " Error: " + e.getMessage());
+ throw new SentryConfigurationException("Error loading policy file " + resourcePath, e);
+ }
+
if(LOGGER.isDebugEnabled()) {
for(String sectionName : ini.getSectionNames()) {
LOGGER.debug("Section: " + sectionName);
@@ -109,7 +128,7 @@ public class SimpleFileProviderBackend implements ProviderBackend {
}
ImmutableSetMultimap<String, String> globalRoles;
Map<String, ImmutableSetMultimap<String, String>> perDatabaseRoles = Maps.newHashMap();
- globalRoles = parseIni(null, ini, validators);
+ globalRoles = parseIni(null, ini, validators, resourcePath);
Ini.Section filesSection = ini.getSection(DATABASES);
if(filesSection == null) {
LOGGER.info("Section " + DATABASES + " needs no further processing");
@@ -124,21 +143,27 @@ public class SimpleFileProviderBackend implements ProviderBackend {
LOGGER.info("Parsing " + perDbPolicy);
Ini perDbIni = PolicyFiles.loadFromPath(perDbPolicy.getFileSystem(conf), perDbPolicy);
if(perDbIni.containsKey(USERS)) {
+ configErrors.add("Per-db policy file cannot contain " + USERS + " section in " + perDbPolicy);
throw new ConfigurationException("Per-db policy files cannot contain " + USERS + " section");
}
if(perDbIni.containsKey(DATABASES)) {
+ configErrors.add("Per-db policy files cannot contain " + DATABASES
+ + " section in " + perDbPolicy);
throw new ConfigurationException("Per-db policy files cannot contain " + DATABASES + " section");
}
- ImmutableSetMultimap<String, String> currentDbRoles = parseIni(database, perDbIni, validators);
+ ImmutableSetMultimap<String, String> currentDbRoles = parseIni(database, perDbIni, validators, perDbPolicy);
perDatabaseRoles.put(database, currentDbRoles);
perDbResources.add(perDbPolicy);
} catch (Exception e) {
+ configErrors.add("Failed to read per-DB policy file " + perDbPolicy +
+ " Error: " + e.getMessage());
LOGGER.error("Error processing key " + entry.getKey() + ", skipping " + entry.getValue(), e);
}
}
}
roles = new Roles(globalRoles, ImmutableMap.copyOf(perDatabaseRoles));
} catch (Exception e) {
+ configErrors.add("Error processing file " + resourcePath + e.getMessage());
LOGGER.error("Error processing file, ignoring " + resourcePath, e);
}
rolesStorage = roles;
@@ -167,26 +192,32 @@ public class SimpleFileProviderBackend implements ProviderBackend {
return result;
}
- private ImmutableSetMultimap<String, String> parseIni(String database, Ini ini, List<? extends RoleValidator> validators) {
+ private ImmutableSetMultimap<String, String> parseIni(String database, Ini ini, List<? extends RoleValidator> validators,
+ Path policyPath) {
Ini.Section privilegesSection = ini.getSection(ROLES);
boolean invalidConfiguration = false;
if (privilegesSection == null) {
- LOGGER.warn("Section {} empty for {}", ROLES, resourcePath);
+ String errMsg = String.format("Section %s empty for %s", ROLES, policyPath);
+ LOGGER.warn(errMsg);
+ configErrors.add(errMsg);
invalidConfiguration = true;
}
Ini.Section groupsSection = ini.getSection(GROUPS);
if (groupsSection == null) {
- LOGGER.warn("Section {} empty for {}", GROUPS, resourcePath);
+ String warnMsg = String.format("Section %s empty for %s", GROUPS, policyPath);
+ LOGGER.warn(warnMsg);
+ configErrors.add(warnMsg);
invalidConfiguration = true;
}
if (!invalidConfiguration) {
- return parsePermissions(database, privilegesSection, groupsSection, validators);
+ return parsePermissions(database, privilegesSection, groupsSection, validators, policyPath);
}
return ImmutableSetMultimap.of();
}
private ImmutableSetMultimap<String, String> parsePermissions(@Nullable String database,
- Ini.Section rolesSection, Ini.Section groupsSection, List<? extends RoleValidator> validators) {
+ Ini.Section rolesSection, Ini.Section groupsSection, List<? extends RoleValidator> validators,
+ Path policyPath) {
ImmutableSetMultimap.Builder<String, String> resultBuilder = ImmutableSetMultimap.builder();
Multimap<String, String> roleNameToPrivilegeMap = HashMultimap
.create();
@@ -195,16 +226,21 @@ public class SimpleFileProviderBackend implements ProviderBackend {
String roleValue = Strings.nullToEmpty(entry.getValue()).trim();
boolean invalidConfiguration = false;
if (roleName.isEmpty()) {
- LOGGER.warn("Empty role name encountered in {}", resourcePath);
+ String errMsg = String.format("Empty role name encountered in %s", policyPath);
+ LOGGER.warn(errMsg);
+ configErrors.add(errMsg);
invalidConfiguration = true;
}
if (roleValue.isEmpty()) {
- LOGGER.warn("Empty role value encountered in {}", resourcePath);
+ String errMsg = String.format("Empty role value encountered in %s", policyPath);
+ LOGGER.warn(errMsg);
+ configErrors.add(errMsg);
invalidConfiguration = true;
}
if (roleNameToPrivilegeMap.containsKey(roleName)) {
- LOGGER.warn("Role {} defined twice in {}", roleName,
- resourcePath);
+ String warnMsg = String.format("Role %s defined twice in %s", roleName, policyPath);
+ LOGGER.warn(warnMsg);
+ configWarnings.add(warnMsg);
}
Set<String> roles = PermissionUtils
.toPermissionStrings(roleValue);
@@ -227,8 +263,10 @@ public class SimpleFileProviderBackend implements ProviderBackend {
resolvedGroupPrivileges.addAll(roleNameToPrivilegeMap
.get(roleName));
} else {
- LOGGER.warn("Role {} for group {} does not exist in privileges section in {}",
- new Object[] { roleName, groupName, resourcePath });
+ String warnMsg = String.format("Role %s for group %s does not exist in privileges section in %s",
+ roleName, groupName, policyPath);
+ LOGGER.warn(warnMsg);
+ configWarnings.add(warnMsg);
}
}
resultBuilder.putAll(groupName, resolvedGroupPrivileges);
@@ -244,4 +282,17 @@ public class SimpleFileProviderBackend implements ProviderBackend {
return rolesStorage;
}
+
+ @Override
+ public void validatePolicy(List<? extends RoleValidator> validators, boolean strictValidation)
+ throws SentryConfigurationException {
+ if ((strictValidation && !configWarnings.isEmpty()) || !configErrors.isEmpty()) {
+ configErrors.add("Failed to process global policy file " + resourcePath);
+ SentryConfigurationException e = new SentryConfigurationException("");
+ e.setConfigErrors(configErrors);
+ e.setConfigWarnings(configWarnings);
+ throw e;
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/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
index a4d4bb3..a50bd24 100644
--- 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
@@ -18,12 +18,18 @@ 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.core.common.SentryConfigurationException;
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.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
+
import org.junit.Test;
+
import static org.junit.Assert.assertSame;
public class TestGetGroupMapping {
@@ -45,6 +51,21 @@ public class TestGetGroupMapping {
public PermissionFactory getPermissionFactory() { return null; }
public ImmutableSetMultimap<String, String> getPermissions(List<? extends Authorizable> authorizables, List<String> groups) { return null; }
+
+ public ImmutableSet<String> listPermissions(String groupName)
+ throws SentryConfigurationException {
+ return null;
+ }
+
+ public ImmutableSet<String> listPermissions(List<String> groupName)
+ throws SentryConfigurationException {
+ return null;
+ }
+
+ public void validatePolicy(boolean strictValidation)
+ throws SentryConfigurationException {
+ return;
+ }
};
TestResourceAuthorizationProvider authProvider =
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java
index 66cd2d1..2f83678 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/Context.java
@@ -209,4 +209,8 @@ public class Context {
public String getProperty(String propName) {
return hiveServer.getProperty(propName);
}
-}
\ No newline at end of file
+
+ public String getConnectionURL() {
+ return hiveServer.getURL();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a4819f5b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestConfigTool.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestConfigTool.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestConfigTool.java
new file mode 100644
index 0000000..6968cc0
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestConfigTool.java
@@ -0,0 +1,304 @@
+/*
+ * 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.hive;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Assert;
+
+import org.apache.sentry.binding.hive.authz.SentryConfigTool;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
+import org.apache.sentry.core.common.SentryConfigurationException;
+import org.apache.sentry.core.common.Subject;
+import org.apache.sentry.provider.file.PolicyFile;
+
+import com.google.common.io.Resources;
+
+public class TestConfigTool extends AbstractTestWithStaticConfiguration {
+ private static final String DB2_POLICY_FILE = "db2-policy-file.ini";
+ private static String prefix;
+
+ private PolicyFile policyFile;
+ private SentryConfigTool configTool;
+
+ @Before
+ public void setup() throws Exception {
+ context = createContext();
+ policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP);
+ configTool = new SentryConfigTool();
+ String hiveServer2 = System.getProperty("sentry.e2etest.hiveServer2Type",
+ "InternalHiveServer2");
+ String policyOnHDFS = System.getProperty(
+ "sentry.e2etest.hive.policyOnHDFS", "true");
+ if (policyOnHDFS.trim().equalsIgnoreCase("true")
+ && (hiveServer2.equals("UnmanagedHiveServer2"))) {
+ String policyLocation = System.getProperty(
+ "sentry.e2etest.hive.policy.location", "/user/hive/sentry");
+ prefix = "hdfs://" + policyLocation + "/";
+ } else {
+ prefix = "file://" + context.getPolicyFile().getParent() + "/";
+ }
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (context != null) {
+ context.close();
+ }
+ }
+
+ /**
+ * Verify errors/warnings from malformed policy file
+ * @throws Exception
+ */
+ @Test
+ public void testInvalidPolicy() throws Exception {
+ // policy file, missing insert_tab2 and select_tab3 role definition
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1",
+ "server=server1->db=db1->table=tab1->action=select")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ policyFile.write(context.getPolicyFile());
+
+ configTool.setPolicyFile(context.getPolicyFile().getPath());
+ configTool.setupConfig();
+ try {
+ configTool.getSentryProvider().validateResource(true);
+ fail("Policy validation should fail for malformed policy");
+ } catch (SentryConfigurationException e) {
+ assertTrue(e
+ .getConfigWarnings()
+ .get(0)
+ .contains(
+ "Role select_tab3 for group " + USERGROUP2 + " does not exist"));
+ assertTrue(e
+ .getConfigWarnings()
+ .get(1)
+ .contains(
+ "Role insert_tab2 for group " + USERGROUP1 + " does not exist"));
+ }
+ }
+
+ /**
+ * Verify errors/warnings from malformed policy file with per-DB policy
+ * @throws Exception
+ */
+ @Test
+ public void testInvalidPerDbPolicy() throws Exception {
+ PolicyFile db2PolicyFile = new PolicyFile();
+ File db2PolicyFileHandle = new File(context.getPolicyFile().getParent(),
+ DB2_POLICY_FILE);
+ // invalid db2 policy file with missing roles
+ db2PolicyFile
+ .addRolesToGroup(USERGROUP2, "select_tbl2", "insert_db2_tab2")
+ .addPermissionsToRole("select_tbl2",
+ "server=server1->db=db2->table=tbl2->action=select")
+ .write(db2PolicyFileHandle);
+
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tbl1")
+ .addRolesToGroup(USERGROUP2, "select_tbl3")
+ .addPermissionsToRole("select_tbl1",
+ "server=server1->db=db1->table=tbl1->action=select")
+ .addDatabase("db2", prefix + db2PolicyFileHandle.getName())
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping())
+ .write(context.getPolicyFile());
+
+ configTool.setPolicyFile(context.getPolicyFile().getPath());
+ configTool.setupConfig();
+ try {
+ configTool.getSentryProvider().validateResource(true);
+ fail("Policy validation should fail for malformed policy");
+ } catch (SentryConfigurationException e) {
+ assertTrue(e
+ .getConfigWarnings()
+ .get(0)
+ .contains(
+ "Role select_tbl3 for group " + USERGROUP2 + " does not exist"));
+ assertTrue(e.getConfigWarnings().get(0)
+ .contains(context.getPolicyFile().getName()));
+ assertTrue(e
+ .getConfigWarnings()
+ .get(1)
+ .contains(
+ "Role insert_db2_tab2 for group " + USERGROUP2
+ + " does not exist"));
+ assertTrue(e.getConfigWarnings().get(1)
+ .contains(db2PolicyFileHandle.getName()));
+ }
+ }
+
+ /**
+ * Validate user permissions listing
+ * @throws Exception
+ */
+ @Test
+ public void testUserPermissions() throws Exception {
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1",
+ "server=server1->db=db1->table=tab1->action=select")
+ .addPermissionsToRole("insert_tab2",
+ "server=server1->db=db1->table=tab2->action=insert")
+ .addPermissionsToRole("select_tab3",
+ "server=server1->db=db1->table=tab3->action=select")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ policyFile.write(context.getPolicyFile());
+
+ configTool.setPolicyFile(context.getPolicyFile().getPath());
+ configTool.setupConfig();
+ configTool.validatePolicy();
+
+ Set<String> permList = configTool.getSentryProvider()
+ .listPermissionsForSubject(new Subject(USER1_1));
+ assertTrue(permList
+ .contains("server=server1->db=db1->table=tab1->action=select"));
+ assertTrue(permList
+ .contains("server=server1->db=db1->table=tab2->action=insert"));
+
+ permList = configTool.getSentryProvider().listPermissionsForSubject(
+ new Subject(USER2_1));
+ assertTrue(permList
+ .contains("server=server1->db=db1->table=tab3->action=select"));
+
+ permList = configTool.getSentryProvider().listPermissionsForSubject(
+ new Subject(ADMIN1));
+ assertTrue(permList.contains("server=server1"));
+ }
+
+ /***
+ * Verify the mock compilation config setting forces query to abort
+ * @throws Exception
+ */
+ @Test
+ public void testMockCompilation() throws Exception {
+ policyFile.setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ policyFile.write(context.getPolicyFile());
+ // setup db objects needed by the test
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+
+ statement.execute("DROP TABLE IF EXISTS tab1");
+ statement.execute("CREATE TABLE tab1(B INT, A STRING) "
+ + " row format delimited fields terminated by '|' stored as textfile");
+ statement.execute("SELECT * FROM tab1");
+
+ statement.execute("SET " + HiveAuthzConf.HIVE_SENTRY_MOCK_COMPILATION
+ + "=true");
+ try {
+ statement.execute("SELECT * FROM tab1");
+ fail("Query should fail with mock error config enabled");
+ } catch (SQLException e) {
+ assertTrue(e.getMessage().contains(HiveAuthzConf.HIVE_SENTRY_MOCK_ERROR));
+ }
+ statement.close();
+
+ }
+
+ /**
+ * verify missing permissions for query using remote query validation
+ * @throws Exception
+ */
+ @Test
+ public void testQueryPermissions() throws Exception {
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1",
+ "server=server1->db=default->table=tab1->action=select")
+ .addPermissionsToRole("insert_tab2",
+ "server=server1->db=default->table=tab2->action=insert")
+ .addPermissionsToRole("select_tab3",
+ "server=server1->db=default->table=tab3->action=select")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ policyFile.write(context.getPolicyFile());
+
+ // setup db objects needed by the test
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+
+ statement.execute("DROP TABLE IF EXISTS tab1");
+ statement.execute("DROP TABLE IF EXISTS tab2");
+ statement.execute("DROP TABLE IF EXISTS tab3");
+ statement.execute("CREATE TABLE tab1(B INT, A STRING) "
+ + " row format delimited fields terminated by '|' stored as textfile");
+ statement.execute("CREATE TABLE tab2(B INT, A STRING) "
+ + " row format delimited fields terminated by '|' stored as textfile");
+ statement.execute("CREATE TABLE tab3(B INT, A STRING) "
+ + " row format delimited fields terminated by '|' stored as textfile");
+ statement.close();
+ connection.close();
+
+ configTool.setPolicyFile(context.getPolicyFile().getPath());
+ configTool.setJdbcURL(context.getConnectionURL());
+ configTool.setUser(USER1_1);
+ configTool.setupConfig();
+ ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
+
+ // user1_1 can query table1
+ configTool.setUser(USER1_1);
+ configTool.verifyRemoteQuery("SELECT COUNT(*) FROM tab1");
+
+ // user1_1 can't select from tab3
+ try {
+ System.setOut(new PrintStream(errBuffer));
+ configTool.setUser(USER1_1);
+ configTool.verifyRemoteQuery("SELECT COUNT(*) FROM tab3");
+ fail("Query should have failed with insufficient perms");
+ } catch (SQLException e) {
+ assertTrue(errBuffer.toString().contains(
+ "Server=server1->Db=default->Table=tab3->action=select"));
+ errBuffer.flush();
+ }
+
+ // user2_1 can select from tab3, but can't insert into tab2
+ try {
+ configTool.setUser(USER2_1);
+ configTool
+ .verifyRemoteQuery("INSERT OVERWRITE TABLE tab2 SELECT * FROM tab3");
+ fail("Query should have failed with insufficient perms");
+ } catch (SQLException e) {
+ assertTrue(errBuffer.toString().contains(
+ "Server=server1->Db=default->Table=tab2->action=insert"));
+ }
+
+ }
+}