SENTRY-2023: Add sentry-shell support for hbase-indexer permissions (Mano Kovacs, reviewed by Sergio Pena)
Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/5a7b0764 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/5a7b0764 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/5a7b0764 Branch: refs/heads/master Commit: 5a7b076435dfe54f9d093fbf892d4b7141634d66 Parents: 01c76e7 Author: Sergio Pena <[email protected]> Authored: Tue Jan 16 14:29:31 2018 -0600 Committer: Sergio Pena <[email protected]> Committed: Tue Jan 16 14:29:31 2018 -0600 ---------------------------------------------------------------------- sentry-provider/sentry-provider-db/pom.xml | 4 + .../persistent/PrivilegeOperatePersistence.java | 2 + .../tools/GenericPrivilegeConverter.java | 10 +- .../generic/tools/SentryConfigToolIndexer.java | 340 ++++++++++++ .../db/generic/tools/SentryShellGeneric.java | 17 +- .../db/generic/tools/SentryShellIndexer.java | 124 +++++ .../provider/db/tools/SentryShellCommon.java | 224 ++++---- .../tools/TestSentryConfigToolIndexer.java | 263 ++++++++++ .../generic/tools/TestSentryShellIndexer.java | 526 +++++++++++++++++++ .../src/test/resources/indexer_case.ini | 26 + .../resources/indexer_config_import_tool.ini | 29 + .../src/test/resources/indexer_invalid.ini | 21 + 12 files changed, 1477 insertions(+), 109 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/pom.xml b/sentry-provider/sentry-provider-db/pom.xml index 192f8c8..db4808d 100644 --- a/sentry-provider/sentry-provider-db/pom.xml +++ b/sentry-provider/sentry-provider-db/pom.xml @@ -112,6 +112,10 @@ limitations under the License. </dependency> <dependency> <groupId>org.apache.sentry</groupId> + <artifactId>sentry-core-model-indexer</artifactId> + </dependency> + <dependency> + <groupId>org.apache.sentry</groupId> <artifactId>sentry-core-model-sqoop</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java index c13e000..9dcfc03 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java @@ -34,6 +34,7 @@ import org.apache.sentry.core.common.Action; import org.apache.sentry.core.common.Authorizable; import org.apache.sentry.core.common.BitFieldAction; import org.apache.sentry.core.common.BitFieldActionFactory; +import org.apache.sentry.core.model.indexer.IndexerActionFactory; import org.apache.sentry.core.model.kafka.KafkaActionFactory; import org.apache.sentry.core.model.solr.SolrActionFactory; import org.apache.sentry.core.model.sqoop.SqoopActionFactory; @@ -70,6 +71,7 @@ public class PrivilegeOperatePersistence { actionFactories.put("solr", new SolrActionFactory()); actionFactories.put("sqoop", new SqoopActionFactory()); actionFactories.put("kafka", KafkaActionFactory.getInstance()); + actionFactories.put("hbaseindexer", new IndexerActionFactory()); } private final Configuration conf; http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/GenericPrivilegeConverter.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/GenericPrivilegeConverter.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/GenericPrivilegeConverter.java index c65b66d..8de543c 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/GenericPrivilegeConverter.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/GenericPrivilegeConverter.java @@ -35,6 +35,8 @@ import org.apache.sentry.core.common.utils.PolicyFileConstants; import org.apache.sentry.core.common.utils.SentryConstants; import org.apache.sentry.core.common.validator.PrivilegeValidator; import org.apache.sentry.core.common.validator.PrivilegeValidatorContext; +import org.apache.sentry.core.model.indexer.IndexerModelAuthorizables; +import org.apache.sentry.core.model.indexer.IndexerPrivilegeModel; import org.apache.sentry.core.model.kafka.KafkaAuthorizable; import org.apache.sentry.core.model.kafka.KafkaModelAuthorizables; import org.apache.sentry.core.model.kafka.KafkaPrivilegeModel; @@ -158,25 +160,29 @@ public class GenericPrivilegeConverter implements TSentryPrivilegeConverter { } } - private List<PrivilegeValidator> getPrivilegeValidators() throws SentryUserException { + protected List<PrivilegeValidator> getPrivilegeValidators() throws SentryUserException { if (AuthorizationComponent.KAFKA.equals(component)) { return KafkaPrivilegeModel.getInstance().getPrivilegeValidators(); } else if ("SOLR".equals(component)) { return SolrPrivilegeModel.getInstance().getPrivilegeValidators(); } else if (AuthorizationComponent.SQOOP.equals(component)) { return SqoopPrivilegeModel.getInstance().getPrivilegeValidators(service); + } else if (AuthorizationComponent.HBASE_INDEXER.equals(component)) { + return IndexerPrivilegeModel.getInstance().getPrivilegeValidators(); } throw new SentryUserException("Invalid component specified for GenericPrivilegeCoverter: " + component); } - private Authorizable getAuthorizable(KeyValue keyValue) throws SentryUserException { + protected Authorizable getAuthorizable(KeyValue keyValue) throws SentryUserException { if (AuthorizationComponent.KAFKA.equals(component)) { return KafkaModelAuthorizables.from(keyValue); } else if ("SOLR".equals(component)) { return SolrModelAuthorizables.from(keyValue); } else if (AuthorizationComponent.SQOOP.equals(component)) { return SqoopModelAuthorizables.from(keyValue); + } else if (AuthorizationComponent.HBASE_INDEXER.equals(component)) { + return IndexerModelAuthorizables.from(keyValue); } throw new SentryUserException("Invalid component specified for GenericPrivilegeCoverter: " + component); http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolIndexer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolIndexer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolIndexer.java new file mode 100644 index 0000000..c2341d3 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolIndexer.java @@ -0,0 +1,340 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.provider.db.generic.tools; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.collect.Table; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.exception.SentryConfigurationException; +import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.model.indexer.IndexerPrivilegeModel; +import org.apache.sentry.provider.common.ProviderBackend; +import org.apache.sentry.provider.common.ProviderBackendContext; +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClientFactory; +import org.apache.sentry.provider.file.SimpleFileProviderBackend; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import static org.apache.sentry.core.common.utils.SentryConstants.AUTHORIZABLE_SPLITTER; +import static org.apache.sentry.provider.common.AuthorizationComponent.HBASE_INDEXER; +import static org.apache.sentry.service.thrift.ServiceConstants.ClientConfig.SERVICE_NAME; + +/** + * SentryConfigToolIndexer is an administrative tool used to parse a HBase Indexer policy file + * and add the role, group mappings, and privileges therein to the Sentry service. + */ +public class SentryConfigToolIndexer { + + private static final Logger LOGGER = LoggerFactory.getLogger(SentryConfigToolIndexer.class); + + private String policyFile; + private boolean validate; + private boolean importPolicy; + private boolean checkCompat; + private String confPath; + + private String serviceName; + + + + public String getPolicyFile() { return policyFile; } + + public boolean getValidate() { return validate; } + public boolean getImportPolicy() { return importPolicy; } + public boolean getCheckCompat() { return checkCompat; } + public String getConfPath() { return confPath; } + public String getServiceName() { + return serviceName; + } + + /** + * Adds command line options for the tool to the passed Options object. Used to extend existing options. + * @param options + */ + public void setupOptions(Options options) { + Option globalPolicyPath = new Option("f", "policy_ini", true, + "Policy file path"); + globalPolicyPath.setRequired(false); + options.addOption(globalPolicyPath); + + Option validateOpt = new Option("v", "validate", false, + "Validate policy file"); + validateOpt.setRequired(false); + options.addOption(validateOpt); + + Option checkCompatOpt = new Option("c","checkcompat",false, + "Check compatibility with Sentry Service"); + checkCompatOpt.setRequired(false); + options.addOption(checkCompatOpt); + + Option importOpt = new Option("i", "import", false, + "Import policy file"); + importOpt.setRequired(false); + options.addOption(importOpt); + + } + + /** + * Parses and processes the arguments from the given command line object. + * @param cmd + */ + public void parseOptions(CommandLine cmd) { + boolean isToolActive = false; + for (Option opt : cmd.getOptions()) { + if (opt.getOpt().equals("mgr")) { + isToolActive = true; + } + } + if (!isToolActive) { + return; + } + for (Option opt : cmd.getOptions()) { + if (opt.getOpt().equals("f")) { + policyFile = opt.getValue(); + } else if (opt.getOpt().equals("v")) { + validate = true; + } else if (opt.getOpt().equals("i")) { + importPolicy = true; + } else if (opt.getOpt().equals("c")) { + checkCompat = true; + } else if (opt.getOpt().equals("conf")) { + confPath = opt.getValue(); + } else if (opt.getOpt().equals("s")) { + serviceName = opt.getValue(); + } + } + if (policyFile == null) { + throw new IllegalArgumentException("Missing required option: f"); + } + if (!validate && !importPolicy) { + throw new IllegalArgumentException("No action specified; at least one of action or import must be specified"); + } + } + + + /** + * Processes the necessary command based on the arguments parsed earlier. + * @throws Exception + */ + public void run() throws Exception { + String component = HBASE_INDEXER; + Configuration conf = getSentryConf(); + + String service = conf.get(SERVICE_NAME, getServiceName()); + + if (service == null) { + throw new IllegalArgumentException("Service was not defined. Please, use -s command option, or sentry.provider.backend.generic.service-name configuration entry."); + } + + LOGGER.info(String.format("Context: component=%s, service=%s", component, service)); + // instantiate a solr client for sentry service. This sets the ugi, so must + // be done before getting the ugi below. + try(SentryGenericServiceClient client = + SentryGenericServiceClientFactory.create(conf)) { + UserGroupInformation ugi = UserGroupInformation.getLoginUser(); + String requestorName = ugi.getShortUserName(); + + convertINIToSentryServiceCmds(component, service, requestorName, conf, client, + getPolicyFile(), getValidate(), getImportPolicy(), getCheckCompat()); + } + } + + private Configuration getSentryConf() { + Configuration conf = new Configuration(); + conf.addResource(new Path(getConfPath())); + return conf; + } + + private void convertINIToSentryServiceCmds(String component, + String service, String requestorName, + Configuration conf, SentryGenericServiceClient client, + String policyFile, boolean validate, boolean importPolicy, + boolean checkCompat) throws Exception { + + //instantiate a file providerBackend for parsing + LOGGER.info("Reading policy file at: " + policyFile); + SimpleFileProviderBackend policyFileBackend = + new SimpleFileProviderBackend(conf, policyFile); + ProviderBackendContext context = new ProviderBackendContext(); + context.setValidators(IndexerPrivilegeModel.getInstance().getPrivilegeValidators()); + policyFileBackend.initialize(context); + if (validate) { + validatePolicy(policyFileBackend); + } + + if (checkCompat) { + checkCompat(policyFileBackend); + } + + //import the relations about group,role and privilege into the DB store + Set<String> roles = Sets.newHashSet(); + Table<String, String, Set<String>> groupRolePrivilegeTable = + policyFileBackend.getGroupRolePrivilegeTable(); + GenericPrivilegeConverter converter = new GenericPrivilegeConverter(component, service, false); + + for (String groupName : groupRolePrivilegeTable.rowKeySet()) { + for (String roleName : groupRolePrivilegeTable.columnKeySet()) { + if (!roles.contains(roleName)) { + LOGGER.info(dryRunMessage(importPolicy) + "Creating role: " + roleName.toLowerCase(Locale.US)); + if (importPolicy) { + client.createRoleIfNotExist(requestorName, roleName, component); + } + roles.add(roleName); + } + + Set<String> privileges = groupRolePrivilegeTable.get(groupName, roleName); + if (privileges == null) { + continue; + } + LOGGER.info(dryRunMessage(importPolicy) + "Adding role: " + roleName.toLowerCase(Locale.US) + " to group: " + groupName); + if (importPolicy) { + client.grantRoleToGroups(requestorName, roleName, component, Sets.newHashSet(groupName)); + } + + for (String permission : privileges) { + String action = null; + + for (String authorizable : AUTHORIZABLE_SPLITTER. + trimResults().split(permission)) { + KeyValue kv = new KeyValue(authorizable); + String key = kv.getKey(); + String value = kv.getValue(); + if ("action".equalsIgnoreCase(key)) { + action = value; + } + } + + // Service doesn't support not specifying action + if (action == null) { + permission += "->action=" + Action.ALL; + } + LOGGER.info(dryRunMessage(importPolicy) + "Adding permission: " + permission + " to role: " + roleName.toLowerCase(Locale.US)); + if (importPolicy) { + client.grantPrivilege(requestorName, roleName, component, converter.fromString(permission)); + } + } + } + } + } + + private void validatePolicy(ProviderBackend backend) throws Exception { + try { + backend.validatePolicy(true); + } catch (SentryConfigurationException e) { + printConfigErrorsWarnings(e); + throw e; + } + } + + private void printConfigErrorsWarnings(SentryConfigurationException configException) { + 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); + } + } + + private void checkCompat(SimpleFileProviderBackend backend) throws Exception { + Map<String, Set<String>> rolesCaseMapping = new HashMap<String, Set<String>>(); + Table<String, String, Set<String>> groupRolePrivilegeTable = + backend.getGroupRolePrivilegeTable(); + + for (String roleName : groupRolePrivilegeTable.columnKeySet()) { + String roleNameLower = roleName.toLowerCase(Locale.US); + if (!roleName.equals(roleNameLower)) { + if (!rolesCaseMapping.containsKey(roleNameLower)) { + rolesCaseMapping.put(roleNameLower, Sets.newHashSet(roleName)); + } else { + rolesCaseMapping.get(roleNameLower).add(roleName); + } + } + } + + List<String> errors = new LinkedList<String>(); + StringBuilder warningString = new StringBuilder(); + if (!rolesCaseMapping.isEmpty()) { + warningString.append("The following roles names will be lower cased when added to the Sentry Service.\n"); + warningString.append("This will cause document-level security to fail to match the role tokens.\n"); + warningString.append("Role names: "); + } + boolean firstWarning = true; + + for (Map.Entry<String, Set<String>> entry : rolesCaseMapping.entrySet()) { + Set<String> caseMapping = entry.getValue(); + if (caseMapping.size() > 1) { + StringBuilder errorString = new StringBuilder(); + errorString.append("The following (cased) roles map to the same role in the sentry service: "); + boolean first = true; + for (String casedRole : caseMapping) { + errorString.append(first ? "" : ", "); + errorString.append(casedRole); + first = false; + } + errorString.append(". Role in service: ").append(entry.getKey()); + errors.add(errorString.toString()); + } + + for (String casedRole : caseMapping) { + warningString.append(firstWarning? "" : ", "); + warningString.append(casedRole); + firstWarning = false; + } + } + + for (String error : errors) { + System.out.println("ERROR: " + error); + } + System.out.println("\n"); + + System.out.println("Warning: " + warningString.toString()); + if (errors.size() > 0) { + SentryConfigurationException ex = + new SentryConfigurationException("Compatibility check failure"); + ex.setConfigErrors(errors); + ex.setConfigWarnings(Lists.<String>asList(warningString.toString(), new String[0])); + throw ex; + } + } + + private String dryRunMessage(boolean importPolicy) { + if (importPolicy) { + return ""; + } else { + return "[Dry Run] "; + } + } + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellGeneric.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellGeneric.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellGeneric.java index 1623f38..907e146 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellGeneric.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellGeneric.java @@ -18,9 +18,7 @@ package org.apache.sentry.provider.db.generic.tools; -import java.util.List; -import java.util.Set; - +import com.google.common.collect.Sets; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; @@ -35,7 +33,8 @@ import org.apache.sentry.provider.db.tools.ShellCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Sets; +import java.util.List; +import java.util.Set; /** * SentryShellGeneric is an admin tool, and responsible for the management of repository. @@ -60,7 +59,7 @@ public class SentryShellGeneric extends SentryShellCommon { SentryGenericServiceClientFactory.create(conf)) { UserGroupInformation ugi = UserGroupInformation.getLoginUser(); String requestorName = ugi.getShortUserName(); - TSentryPrivilegeConverter converter = new GenericPrivilegeConverter(component, service); + TSentryPrivilegeConverter converter = getPrivilegeConverter(component, service); ShellCommand command = new GenericShellCommand(client, component, service, converter); // check the requestor name @@ -102,7 +101,11 @@ public class SentryShellGeneric extends SentryShellCommon { } } - private String getComponent() throws Exception { + protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service) { + return new GenericPrivilegeConverter(component, service); + } + + protected String getComponent() throws Exception { if (type == TYPE.kafka) { return AuthorizationComponent.KAFKA; } else if (type == TYPE.solr) { @@ -114,7 +117,7 @@ public class SentryShellGeneric extends SentryShellCommon { throw new Exception("Invalid type specified for SentryShellGeneric: " + type); } - private String getService(Configuration conf) throws Exception { + protected String getService(Configuration conf) throws Exception { if (type == TYPE.kafka) { return conf.get(KAFKA_SERVICE_NAME, AuthorizationComponent.KAFKA); } else if (type == TYPE.solr) { http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellIndexer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellIndexer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellIndexer.java new file mode 100644 index 0000000..5bbe772 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellIndexer.java @@ -0,0 +1,124 @@ +/** + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.provider.db.generic.tools; + +import org.apache.commons.cli.CommandLine; +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.hadoop.conf.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.sentry.provider.common.AuthorizationComponent.HBASE_INDEXER; +import static org.apache.sentry.service.thrift.ServiceConstants.ClientConfig.SERVICE_NAME; + +/** + * SentryShellIndexer is an admin tool, and responsible for the management of repository. + * The following commands are supported: + * create role, drop role, add group to role, grant privilege to role, + * revoke privilege from role, list roles, list privilege for role. + */ +public class SentryShellIndexer extends SentryShellGeneric { + + protected boolean isMigration = false; + + private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellIndexer.class); + + private final SentryConfigToolIndexer configTool = new SentryConfigToolIndexer(); + + @Override + protected void setupOptions(Options simpleShellOptions) { + super.setupOptions(simpleShellOptions); + configTool.setupOptions(simpleShellOptions); + } + + @Override + protected void parseOptions(CommandLine cmd) throws ParseException { + super.parseOptions(cmd); + configTool.parseOptions(cmd); + for (Option opt : cmd.getOptions()) { + if (opt.getOpt().equals("mgr")) { + isMigration = true; + } + } + } + + @Override + protected OptionGroup getMainOptions() { + OptionGroup mainOptions = super.getMainOptions(); + Option mgrOpt = new Option("mgr", "migrate", false, "Migrate ini file to Sentry service"); + mgrOpt.setRequired(false); + mainOptions.addOption(mgrOpt); + return mainOptions; + } + + /** + * Processes the necessary command based on the arguments parsed earlier. + * @throws Exception + */ + @Override + public void run() throws Exception { + + if (isMigration) { + configTool.run(); + return; + } + + super.run(); + } + + @Override + protected String getComponent() throws Exception { + return HBASE_INDEXER; + } + + @Override + protected String getService(Configuration conf) throws Exception { + String service = conf.get(SERVICE_NAME, serviceName); + if (service == null) { + throw new IllegalArgumentException("Service was not defined. Please, use -s command option, or sentry.provider.backend.generic.service-name configuration entry."); + } + return service; + } + + /** + * Entry-point for Hbase indexer cli tool. + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + SentryShellIndexer sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + Throwable current = e; + // find the first printable message; + while (current != null && current.getMessage() == null) { + current = current.getCause(); + } + System.out.println("The operation failed." + + (current.getMessage() == null ? "" : " Message: " + current.getMessage())); + System.exit(1); + } + } + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java index 5fbc961..c8b2eef 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java @@ -43,11 +43,13 @@ abstract public class SentryShellCommon { public static final String OPTION_DESC_ROLE_NAME = "Role name"; public static final String OPTION_DESC_GROUP_NAME = "Group name"; public static final String OPTION_DESC_PRIVILEGE = "Privilege string"; + public final static String OPTION_DESC_SERVICE = "Name of the service being managed"; public static final String PREFIX_MESSAGE_MISSING_OPTION = "Missing required option: "; public static final String GROUP_SPLIT_CHAR = ","; protected String roleName; + protected String serviceName; protected String groupName; protected String privilegeStr; protected String confPath; @@ -90,47 +92,52 @@ abstract public class SentryShellCommon { protected boolean parseArgs(String[] args) { Options simpleShellOptions = new Options(); - Option crOpt = new Option("cr", "create_role", false, "Create role"); - crOpt.setRequired(false); + setupOptions(simpleShellOptions); - Option drOpt = new Option("dr", "drop_role", false, "Drop role"); - drOpt.setRequired(false); - Option argOpt = new Option("arg", "add_role_group", false, "Add role to group"); - argOpt.setRequired(false); - Option drgOpt = new Option("drg", "delete_role_group", false, "Delete role from group"); - drgOpt.setRequired(false); + // help option + Option helpOpt = new Option("h", "help", false, OPTION_DESC_HELP); + helpOpt.setRequired(false); + simpleShellOptions.addOption(helpOpt); - Option gprOpt = new Option("gpr", "grant_privilege_role", false, "Grant privilege to role"); - gprOpt.setRequired(false); + // this Options is parsed first for help option + Options helpOptions = new Options(); + helpOptions.addOption(helpOpt); - Option rprOpt = new Option("rpr", "revoke_privilege_role", false, "Revoke privilege from role"); - rprOpt.setRequired(false); + try { + Parser parser = new GnuParser(); - Option lrOpt = new Option("lr", "list_role", false, "List role"); - lrOpt.setRequired(false); + // parse help option first + CommandLine cmd = parser.parse(helpOptions, args, true); + for (Option opt : cmd.getOptions()) { + if (opt.getOpt().equals("h")) { + // get the help option, print the usage and exit + usage(simpleShellOptions); + return false; + } + } - Option lpOpt = new Option("lp", "list_privilege", false, "List privilege"); - lpOpt.setRequired(false); + // without help option + cmd = parser.parse(simpleShellOptions, args); - Option lgOpt = new Option("lg", "list_group", false, "List groups"); - lgOpt.setRequired(false); + parseOptions(cmd); + } catch (ParseException pe) { + System.out.println(pe.getMessage()); + usage(simpleShellOptions); + return false; + } + return true; + } - // required args group - OptionGroup simpleShellOptGroup = new OptionGroup(); - simpleShellOptGroup.addOption(crOpt); - simpleShellOptGroup.addOption(drOpt); - simpleShellOptGroup.addOption(argOpt); - simpleShellOptGroup.addOption(drgOpt); - simpleShellOptGroup.addOption(gprOpt); - simpleShellOptGroup.addOption(rprOpt); - simpleShellOptGroup.addOption(lrOpt); - simpleShellOptGroup.addOption(lpOpt); - simpleShellOptGroup.addOption(lgOpt); - simpleShellOptGroup.setRequired(true); + protected void setupOptions(Options simpleShellOptions) { + OptionGroup simpleShellOptGroup = getMainOptions(); simpleShellOptions.addOptionGroup(simpleShellOptGroup); + Option sOpt = new Option("s", "service", true, OPTION_DESC_SERVICE); + sOpt.setRequired(false); + simpleShellOptions.addOption(sOpt); + // optional args Option pOpt = new Option("p", "privilege", true, OPTION_DESC_PRIVILEGE); pOpt.setRequired(false); @@ -153,86 +160,103 @@ abstract public class SentryShellCommon { Option sentrySitePathOpt = new Option("conf", "sentry_conf", true, OPTION_DESC_CONF); sentrySitePathOpt.setRequired(true); simpleShellOptions.addOption(sentrySitePathOpt); + } - // help option - Option helpOpt = new Option("h", "help", false, OPTION_DESC_HELP); - helpOpt.setRequired(false); - simpleShellOptions.addOption(helpOpt); + protected OptionGroup getMainOptions() { + OptionGroup simpleShellOptGroup = new OptionGroup(); + Option crOpt = new Option("cr", "create_role", false, "Create role"); + crOpt.setRequired(false); - // this Options is parsed first for help option - Options helpOptions = new Options(); - helpOptions.addOption(helpOpt); + Option drOpt = new Option("dr", "drop_role", false, "Drop role"); + drOpt.setRequired(false); - try { - Parser parser = new GnuParser(); + Option argOpt = new Option("arg", "add_role_group", false, "Add role to group"); + argOpt.setRequired(false); - // parse help option first - CommandLine cmd = parser.parse(helpOptions, args, true); - for (Option opt : cmd.getOptions()) { - if (opt.getOpt().equals("h")) { - // get the help option, print the usage and exit - usage(simpleShellOptions); - return false; - } - } + Option drgOpt = new Option("drg", "delete_role_group", false, "Delete role from group"); + drgOpt.setRequired(false); - // without help option - cmd = parser.parse(simpleShellOptions, args); + Option gprOpt = new Option("gpr", "grant_privilege_role", false, "Grant privilege to role"); + gprOpt.setRequired(false); - for (Option opt : cmd.getOptions()) { - if (opt.getOpt().equals("p")) { - privilegeStr = opt.getValue(); - } else if (opt.getOpt().equals("g")) { - groupName = opt.getValue(); - } else if (opt.getOpt().equals("r")) { - roleName = opt.getValue(); - } else if (opt.getOpt().equals("cr")) { - isCreateRole = true; - roleNameRequired = true; - } else if (opt.getOpt().equals("dr")) { - isDropRole = true; - roleNameRequired = true; - } else if (opt.getOpt().equals("arg")) { - isAddRoleGroup = true; - roleNameRequired = true; - groupNameRequired = true; - } else if (opt.getOpt().equals("drg")) { - isDeleteRoleGroup = true; - roleNameRequired = true; - groupNameRequired = true; - } else if (opt.getOpt().equals("gpr")) { - isGrantPrivilegeRole = true; - roleNameRequired = true; - privilegeStrRequired = true; - } else if (opt.getOpt().equals("rpr")) { - isRevokePrivilegeRole = true; - roleNameRequired = true; - privilegeStrRequired = true; - } else if (opt.getOpt().equals("lr")) { - isListRole = true; - } else if (opt.getOpt().equals("lp")) { - isListPrivilege = true; - roleNameRequired = true; - } else if (opt.getOpt().equals("lg")) { - isListGroup = true; - } else if (opt.getOpt().equals("conf")) { - confPath = opt.getValue(); - } else if (opt.getOpt().equals("t")) { - type = TYPE.valueOf(opt.getValue()); - } + Option rprOpt = new Option("rpr", "revoke_privilege_role", false, "Revoke privilege from role"); + rprOpt.setRequired(false); + + Option lrOpt = new Option("lr", "list_role", false, "List role"); + lrOpt.setRequired(false); + + Option lpOpt = new Option("lp", "list_privilege", false, "List privilege"); + lpOpt.setRequired(false); + + Option lgOpt = new Option("lg", "list_group", false, "List groups"); + lgOpt.setRequired(false); + + + // required args group + simpleShellOptGroup.addOption(crOpt); + simpleShellOptGroup.addOption(drOpt); + simpleShellOptGroup.addOption(argOpt); + simpleShellOptGroup.addOption(drgOpt); + simpleShellOptGroup.addOption(gprOpt); + simpleShellOptGroup.addOption(rprOpt); + simpleShellOptGroup.addOption(lrOpt); + simpleShellOptGroup.addOption(lpOpt); + simpleShellOptGroup.addOption(lgOpt); + simpleShellOptGroup.setRequired(true); + return simpleShellOptGroup; + } + + protected void parseOptions(CommandLine cmd) throws ParseException { + for (Option opt : cmd.getOptions()) { + if (opt.getOpt().equals("p")) { + privilegeStr = opt.getValue(); + } else if (opt.getOpt().equals("g")) { + groupName = opt.getValue(); + } else if (opt.getOpt().equals("r")) { + roleName = opt.getValue(); + } else if (opt.getOpt().equals("s")) { + serviceName = opt.getValue(); + } else if (opt.getOpt().equals("cr")) { + isCreateRole = true; + roleNameRequired = true; + } else if (opt.getOpt().equals("dr")) { + isDropRole = true; + roleNameRequired = true; + } else if (opt.getOpt().equals("arg")) { + isAddRoleGroup = true; + roleNameRequired = true; + groupNameRequired = true; + } else if (opt.getOpt().equals("drg")) { + isDeleteRoleGroup = true; + roleNameRequired = true; + groupNameRequired = true; + } else if (opt.getOpt().equals("gpr")) { + isGrantPrivilegeRole = true; + roleNameRequired = true; + privilegeStrRequired = true; + } else if (opt.getOpt().equals("rpr")) { + isRevokePrivilegeRole = true; + roleNameRequired = true; + privilegeStrRequired = true; + } else if (opt.getOpt().equals("lr")) { + isListRole = true; + } else if (opt.getOpt().equals("lp")) { + isListPrivilege = true; + roleNameRequired = true; + } else if (opt.getOpt().equals("lg")) { + isListGroup = true; + } else if (opt.getOpt().equals("conf")) { + confPath = opt.getValue(); + } else if (opt.getOpt().equals("t")) { + type = TYPE.valueOf(opt.getValue()); } - checkRequiredParameter(roleNameRequired, roleName, OPTION_DESC_ROLE_NAME); - checkRequiredParameter(groupNameRequired, groupName, OPTION_DESC_GROUP_NAME); - checkRequiredParameter(privilegeStrRequired, privilegeStr, OPTION_DESC_PRIVILEGE); - } catch (ParseException pe) { - System.out.println(pe.getMessage()); - usage(simpleShellOptions); - return false; } - return true; + checkRequiredParameter(roleNameRequired, roleName, OPTION_DESC_ROLE_NAME); + checkRequiredParameter(groupNameRequired, groupName, OPTION_DESC_GROUP_NAME); + checkRequiredParameter(privilegeStrRequired, privilegeStr, OPTION_DESC_PRIVILEGE); } - private void checkRequiredParameter(boolean isRequired, String paramValue, String paramName) throws ParseException { + protected void checkRequiredParameter(boolean isRequired, String paramValue, String paramName) throws ParseException { if (isRequired && StringUtils.isEmpty(paramValue)) { throw new ParseException(PREFIX_MESSAGE_MISSING_OPTION + paramName); } http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolIndexer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolIndexer.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolIndexer.java new file mode 100644 index 0000000..4dddf78 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolIndexer.java @@ -0,0 +1,263 @@ + /** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.provider.db.generic.tools; + + import com.google.common.collect.Sets; + import com.google.common.io.Files; + import org.apache.commons.io.FileUtils; + import org.apache.sentry.core.common.exception.SentryConfigurationException; + import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceIntegrationBase; + import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; + import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole; + import org.apache.sentry.service.thrift.ServiceConstants; + import org.junit.After; + import org.junit.Before; + import org.junit.Test; + + import java.io.File; + import java.io.FileOutputStream; + import java.util.HashMap; + import java.util.HashSet; + import java.util.Map; + import java.util.Set; + + import static org.apache.sentry.provider.common.AuthorizationComponent.HBASE_INDEXER; + import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertTrue; + import static org.junit.Assert.fail; + + public class TestSentryConfigToolIndexer extends SentryGenericServiceIntegrationBase { + private static String RESOURCES_DIR = "target" + File.separator + "test-classes" + File.separator; + private static String VALID_POLICY_INI = RESOURCES_DIR + "indexer_config_import_tool.ini"; + private static String INVALID_POLICY_INI = RESOURCES_DIR + "indexer_invalid.ini"; + private static String CASE_POLICY_INI = RESOURCES_DIR + "indexer_case.ini"; + private File confDir; + private File confPath; + private String requestorName = ""; + private String service = "service1"; + + @Before + public void prepareForTest() throws Exception { + confDir = Files.createTempDir(); + confPath = new File(confDir, "sentry-site.xml"); + conf.set(ServiceConstants.ClientConfig.SERVICE_NAME, service); + if (confPath.createNewFile()) { + FileOutputStream to = new FileOutputStream(confPath); + conf.writeXml(to); + to.close(); + } + requestorName = clientUgi.getShortUserName();//System.getProperty("user.name", ""); + Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP); + setLocalGroupMapping(requestorName, requestorUserGroupNames); + // add ADMIN_USER for the after() in SentryServiceIntegrationBase + setLocalGroupMapping(ADMIN_USER, requestorUserGroupNames); + writePolicyFile(); + } + + @After + public void clearTestData() throws Exception { + FileUtils.deleteQuietly(confDir); + + // clear roles and privileges + Set<TSentryRole> tRoles = client.listAllRoles(requestorName, HBASE_INDEXER); + for (TSentryRole tRole : tRoles) { + String role = tRole.getRoleName(); + Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName( + requestorName, role, HBASE_INDEXER, service); + for (TSentryPrivilege privilege : privileges) { + client.revokePrivilege(requestorName, role, HBASE_INDEXER, privilege); + } + client.dropRole(requestorName, role, HBASE_INDEXER); + } + } + + @Test + public void testConvertIni() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + String[] args = {"-mgr", "-f", VALID_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-v", "-i"}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + sentryTool.executeShell(args); + + Map<String, Set<String>> groupMapping = new HashMap<String, Set<String>>(); + groupMapping.put("corporal_role", Sets.newHashSet("corporal", "sergeant", "general", "commander_in_chief")); + groupMapping.put("sergeant_role", Sets.newHashSet("sergeant", "general", "commander_in_chief")); + groupMapping.put("general_role", Sets.newHashSet("general", "commander_in_chief")); + groupMapping.put("commander_in_chief_role", Sets.newHashSet("commander_in_chief")); + + + Map<String, Set<String>> privilegeMapping = new HashMap<String, Set<String>>(); + privilegeMapping.put("corporal_role", + Sets.newHashSet("Indexer=info->action=read", "Indexer=info->action=write")); + privilegeMapping.put("sergeant_role", + Sets.newHashSet("Indexer=info->action=write")); + privilegeMapping.put("general_role", + Sets.newHashSet("Indexer=info->action=*")); + privilegeMapping.put("commander_in_chief_role", + Sets.newHashSet("Indexer=*->action=*")); + + // check roles + Set<TSentryRole> tRoles = client.listAllRoles(requestorName, HBASE_INDEXER); + assertEquals("Unexpected number of roles", groupMapping.keySet().size(), tRoles.size()); + Set<String> roles = new HashSet<String>(); + for (TSentryRole tRole : tRoles) { + roles.add(tRole.getRoleName()); + } + + for (String expectedRole : groupMapping.keySet()) { + assertTrue("Didn't find expected role: " + expectedRole, roles.contains(expectedRole)); + } + + // check groups + for (TSentryRole tRole : tRoles) { + Set<String> expectedGroups = groupMapping.get(tRole.getRoleName()); + assertEquals("Group size doesn't match for role: " + tRole.getRoleName(), + expectedGroups.size(), tRole.getGroups().size()); + assertTrue("Group does not contain all expected members for role: " + tRole.getRoleName(), + tRole.getGroups().containsAll(expectedGroups)); + } + + // check privileges + GenericPrivilegeConverter convert = new GenericPrivilegeConverter(HBASE_INDEXER, service); + for (String role : roles) { + Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName( + requestorName, role, HBASE_INDEXER, service); + Set<String> expectedPrivileges = privilegeMapping.get(role); + assertEquals("Privilege set size doesn't match for role: " + role, + expectedPrivileges.size(), privileges.size()); + + Set<String> privilegeStrs = new HashSet<String>(); + for (TSentryPrivilege privilege : privileges) { + privilegeStrs.add(convert.toString(privilege)); + } + + for (String expectedPrivilege : expectedPrivileges) { + assertTrue("Did not find expected privilege: " + expectedPrivilege, + privilegeStrs.contains(expectedPrivilege)); + } + } + } + }); + } + + @Test + public void testNoPolicyFile() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + String[] args = { "-mgr", "-f", INVALID_POLICY_INI + "Foobar", "-conf", confPath.getAbsolutePath(), "-v", "-i"}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + try { + sentryTool.executeShell(args); + fail("Exception should be thrown for nonexistant ini"); + } catch (SentryConfigurationException e) { + // expected exception + } + } + }); + } + + @Test + public void testNoValidateNorImport() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + String[] args = { "-mgr", "-f", INVALID_POLICY_INI, "-conf", confPath.getAbsolutePath()}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + try { + sentryTool.executeShell(args); + fail("Exception should be thrown for validating invalid ini"); + } catch (IllegalArgumentException e) { + // expected exception + } + } + }); + } + + @Test + public void testConvertInvalidIni() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // test: validate an invalid ini + String[] args = { "-mgr", "-f", INVALID_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-v", "-i"}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + try { + sentryTool.executeShell(args); + fail("Exception should be thrown for validating invalid ini"); + } catch (SentryConfigurationException e) { + // expected exception + } + + // test without validating, should not error + args = new String[] { "-mgr", "-f", INVALID_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-i"}; + sentryTool = new SentryShellIndexer(); + sentryTool.executeShell(args); + } + }); + } + + @Test + public void testCompatCheck() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // test: validate an invalid ini + String[] args = { "-mgr", "-f", CASE_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-v", "-i", "-c"}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + try { + sentryTool.executeShell(args); + fail("Exception should be thrown for validating invalid ini"); + } catch (SentryConfigurationException e) { + assertEquals("Expected error", 1, e.getConfigErrors().size()); + String error = e.getConfigErrors().get(0); + assertCasedRoleNamesInMessage(error, "RoLe1", "rOlE1"); + String warning = e.getConfigWarnings().get(0); + assertCasedRoleNamesInMessage(warning, "ROLE2", "RoLe1", "rOlE1"); + assertEquals("Expected warning", 1, e.getConfigWarnings().size()); + } + + // test without compat checking + args = new String[] { "-mgr", "-f", CASE_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-i", "-v"}; + sentryTool = new SentryShellIndexer(); + sentryTool.executeShell(args); + } + }); + } + + // Test that a valid compat check doesn't throw an exception + @Test + public void testCompatCheckValid() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + String[] args = { "-mgr", "-f", VALID_POLICY_INI, "-conf", confPath.getAbsolutePath(), "-v", "-i", "-c"}; + SentryShellIndexer sentryTool = new SentryShellIndexer(); + sentryTool.executeShell(args); + } + }); + } + + private void assertCasedRoleNamesInMessage(String message, String ... casedRoleNames) { + for (String casedRoleName : casedRoleNames) { + assertTrue("Expected cased role name: " + casedRoleName, message.contains(casedRoleName)); + } + } + } http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellIndexer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellIndexer.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellIndexer.java new file mode 100644 index 0000000..f66eb85 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellIndexer.java @@ -0,0 +1,526 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.provider.db.generic.tools; + +import com.google.common.collect.Sets; +import com.google.common.io.Files; +import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.common.exception.SentryUserException; +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceIntegrationBase; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole; +import org.apache.sentry.provider.db.tools.SentryShellCommon; +import org.apache.sentry.service.thrift.ServiceConstants; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import static junit.framework.Assert.assertEquals; +import static org.apache.sentry.provider.common.AuthorizationComponent.HBASE_INDEXER; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TestSentryShellIndexer extends SentryGenericServiceIntegrationBase { + private File confDir; + private File confPath; + private static String TEST_ROLE_NAME_1 = "testRole1"; + private static String TEST_ROLE_NAME_2 = "testRole2"; + private String requestorName = ""; + private String service = "service1"; + + @Before + public void prepareForTest() throws Exception { + confDir = Files.createTempDir(); + confPath = new File(confDir, "sentry-site.xml"); + conf.set(ServiceConstants.ClientConfig.SERVICE_NAME, service); + if (confPath.createNewFile()) { + FileOutputStream to = new FileOutputStream(confPath); + conf.writeXml(to); + to.close(); + } + requestorName = clientUgi.getShortUserName(); + Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP); + setLocalGroupMapping(requestorName, requestorUserGroupNames); + // add ADMIN_USER for the after() in SentryServiceIntegrationBase + setLocalGroupMapping(ADMIN_USER, requestorUserGroupNames); + writePolicyFile(); + } + + @After + public void clearTestData() throws Exception { + FileUtils.deleteQuietly(confDir); + } + + @Test + public void testCreateDropRole() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // test: create role with -cr + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: create role with --create_role + args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + + // validate the result, list roles with -lr + args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2); + + // validate the result, list roles with --list_role + args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2); + + // test: drop role with -dr + args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: drop role with --drop_role + args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + + // validate the result + Set<TSentryRole> roles = client.listAllRoles(requestorName, HBASE_INDEXER); + assertEquals("Incorrect number of roles", 0, roles.size()); + } + }); + } + + @Test + public void testAddDeleteRoleForGroup() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // Group names are case sensitive - mixed case names should work + String TEST_GROUP_1 = "testGroup1"; + String TEST_GROUP_2 = "testGroup2"; + String TEST_GROUP_3 = "testGroup3"; + + // create the role for test + client.createRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + client.createRole(requestorName, TEST_ROLE_NAME_2, HBASE_INDEXER); + // test: add role to group with -arg + String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: add role to multiple groups + args = new String[] { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3, + "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: add role to group with --add_role_group + args = new String[] { "--add_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1, + "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + + // validate the result list roles with -lr and -g + args = new String[] { "-lr", "-g", TEST_GROUP_1, "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2); + + // list roles with --list_role and -g + args = new String[] { "--list_role", "-g", TEST_GROUP_2, "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1); + + args = new String[] { "--list_role", "-g", TEST_GROUP_3, "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1); + + // test: delete role from group with -drg + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: delete role to multiple groups + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3, + "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + // test: delete role from group with --delete_role_group + args = new String[] { "--delete_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1, + "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + + // validate the result + Set<TSentryRole> roles = client.listRolesByGroupName(requestorName, TEST_GROUP_1, HBASE_INDEXER); + assertEquals("Incorrect number of roles", 0, roles.size()); + roles = client.listRolesByGroupName(requestorName, TEST_GROUP_2, HBASE_INDEXER); + assertEquals("Incorrect number of roles", 0, roles.size()); + roles = client.listRolesByGroupName(requestorName, TEST_GROUP_3, HBASE_INDEXER); + assertEquals("Incorrect number of roles", 0, roles.size()); + // clear the test data + client.dropRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + client.dropRole(requestorName, TEST_ROLE_NAME_2, HBASE_INDEXER); + } + }); + } + + @Test + public void testCaseSensitiveGroupName() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + + // create the role for test + client.createRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + // add role to a group (lower case) + String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", "group1", "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + + // validate the roles when group name is same case as above + args = new String[] { "-lr", "-g", "group1", "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames, TEST_ROLE_NAME_1); + + // roles should be empty when group name is different case than above + args = new String[] { "-lr", "-g", "GROUP1", "-conf", confPath.getAbsolutePath() }; + roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + validateRoleNames(roleNames); + } + }); + } + + public static String grant(boolean shortOption) { + return shortOption ? "-gpr" : "--grant_privilege_role"; + } + + public static String revoke(boolean shortOption) { + return shortOption ? "-rpr" : "--revoke_privilege_role"; + } + + public static String list(boolean shortOption) { + return shortOption ? "-lp" : "--list_privilege"; + } + + private void assertGrantRevokePrivilege(final boolean shortOption) throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // create the role for test + client.createRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + client.createRole(requestorName, TEST_ROLE_NAME_2, HBASE_INDEXER); + + String [] privs = { + "Indexer=*->action=*", + "Indexer=indexer1->action=read", + "Indexer=indexer2->action=write" + }; + for (int i = 0; i < privs.length; ++i) { + // test: grant privilege to role + String [] args = new String [] { grant(shortOption), "-r", TEST_ROLE_NAME_1, "-p", + privs[ i ], + "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + } + + // test the list privilege + String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true); + assertEquals("Incorrect number of privileges", privs.length, privilegeStrs.size()); + for (int i = 0; i < privs.length; ++i) { + assertTrue("Expected privilege: " + privs[ i ], privilegeStrs.contains(privs[ i ])); + } + + for (int i = 0; i < privs.length; ++i) { + args = new String[] { revoke(shortOption), "-r", TEST_ROLE_NAME_1, "-p", + privs[ i ], "-conf", + confPath.getAbsolutePath() }; + SentryShellIndexer.main(args); + Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName(requestorName, + TEST_ROLE_NAME_1, HBASE_INDEXER, service); + assertEquals("Incorrect number of privileges", privs.length - (i + 1), privileges.size()); + } + + // clear the test data + client.dropRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + client.dropRole(requestorName, TEST_ROLE_NAME_2, HBASE_INDEXER); + } + }); + } + + + @Test + public void testGrantRevokePrivilegeWithShortOption() throws Exception { + assertGrantRevokePrivilege(true); + } + + @Test + public void testGrantRevokePrivilegeWithLongOption() throws Exception { + assertGrantRevokePrivilege(false); + } + + @Test + public void testNegativeCaseWithInvalidArgument() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + client.createRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + // test: create duplicate role with -cr + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for creating duplicate role"); + } catch (SentryUserException e) { + // expected exception + } + + // test: drop non-exist role with -dr + args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for dropping non-exist role"); + } catch (SentryUserException e) { + // excepted exception + } + + // test: add non-exist role to group with -arg + args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for granting non-exist role to group"); + } catch (SentryUserException e) { + // excepted exception + } + + // test: drop group from non-exist role with -drg + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for drop group from non-exist role"); + } catch (SentryUserException e) { + // excepted exception + } + + // test: grant privilege to role with the error privilege format + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", "serverserver1->action=*", + "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for the error privilege format, invalid key value."); + } catch (IllegalArgumentException e) { + // excepted exception + } + + // test: grant privilege to role with the error privilege hierarchy + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", + "server=server1->table=tbl1->column=col2->action=insert", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for the error privilege format, invalid key value."); + } catch (IllegalArgumentException e) { + // expected exception + } + + // clear the test data + client.dropRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + } + }); + } + + @Test + public void testNegativeCaseWithoutRequiredArgument() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + String strOptionConf = "conf"; + client.createRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + // test: the conf is required argument + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 }; + SentryShellIndexer sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + strOptionConf); + + // test: -r is required when create role + args = new String[] { "-cr", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -r is required when drop role + args = new String[] { "-dr", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -r is required when add role to group + args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -g is required when add role to group + args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME); + + // test: -r is required when delete role from group + args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -g is required when delete role from group + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME); + + // test: -r is required when grant privilege to role + args = new String[] { "-gpr", "-p", "indexer=Indexer1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -p is required when grant privilege to role + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE); + + // test: action is required in privilege + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-p", "indexer=Indexer1" }; + sentryShell = new SentryShellIndexer(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assert("Privilege is invalid: action required but not specified.".equals(e.getMessage())); + } + + // test: -r is required when revoke privilege from role + args = new String[] { "-rpr", "-p", "indexer=Indexer1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -p is required when revoke privilege from role + args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE); + + // test: command option is required for shell + args = new String[] {"-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellIndexer(); + validateMissingParameterMsgsContains(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[", + "-arg Add role to group", + "-cr Create role", + "-rpr Revoke privilege from role", + "-drg Delete role from group", + "-lr List role", + "-lp List privilege", + "-gpr Grant privilege to role", + "-dr Drop role"); + + // clear the test data + client.dropRole(requestorName, TEST_ROLE_NAME_1, HBASE_INDEXER); + } + }); + } + + // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result. + private Set<String> getShellResultWithOSRedirect(SentryShellIndexer sentryShell, + String[] args, boolean expectedExecuteResult) throws Exception { + PrintStream oldOut = System.out; + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + assertEquals(expectedExecuteResult, sentryShell.executeShell(args)); + String outContentStr = outContent.toString(); + Set<String> resultSet = outContentStr.length() > 0 ? Sets.<String>newHashSet(outContentStr.split("\n")) : Sets.<String>newHashSet(); + System.setOut(oldOut); + return resultSet; + } + + private void validateRoleNames(Set<String> roleNames, String ... expectedRoleNames) { + if (expectedRoleNames != null && expectedRoleNames.length > 0) { + assertEquals("Found: " + roleNames.size() + " roles, expected: " + expectedRoleNames.length, + expectedRoleNames.length, roleNames.size()); + Set<String> lowerCaseRoles = new HashSet<String>(); + for (String role : roleNames) { + lowerCaseRoles.add(role.toLowerCase()); + } + + for (String expectedRole : expectedRoleNames) { + assertTrue("Expected role: " + expectedRole, + lowerCaseRoles.contains(expectedRole.toLowerCase())); + } + } + } + + private void validateMissingParameterMsg(SentryShellIndexer sentryShell, String[] args, + String expectedErrorMsg) throws Exception { + Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false); + assertTrue("Expected error message: " + expectedErrorMsg, errorMsgs.contains(expectedErrorMsg)); + } + + private void validateMissingParameterMsgsContains(SentryShellIndexer sentryShell, String[] args, + String ... expectedErrorMsgsContains) throws Exception { + Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false); + boolean foundAllMessages = false; + Iterator<String> it = errorMsgs.iterator(); + while (it.hasNext()) { + String errorMessage = it.next(); + boolean missingExpected = false; + for (String expectedContains : expectedErrorMsgsContains) { + if (!errorMessage.contains(expectedContains)) { + missingExpected = true; + break; + } + } + if (!missingExpected) { + foundAllMessages = true; + break; + } + } + assertTrue(foundAllMessages); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/test/resources/indexer_case.ini ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/resources/indexer_case.ini b/sentry-provider/sentry-provider-db/src/test/resources/indexer_case.ini new file mode 100644 index 0000000..f1afe1f --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/resources/indexer_case.ini @@ -0,0 +1,26 @@ +# 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. + +[groups] +groupa = RoLe1 +groupb = rOlE1 +groupc = ROLE2 + +[roles] +RoLe1 = indexer=* +rOlE1 = indexer=* +ROLE2 = indexer=* http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/test/resources/indexer_config_import_tool.ini ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/resources/indexer_config_import_tool.ini b/sentry-provider/sentry-provider-db/src/test/resources/indexer_config_import_tool.ini new file mode 100644 index 0000000..c1bfe4b --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/resources/indexer_config_import_tool.ini @@ -0,0 +1,29 @@ +# 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. + +[groups] +corporal = corporal_role +sergeant = corporal_role, sergeant_role +general = corporal_role, sergeant_role, general_role +commander_in_chief = corporal_role, sergeant_role, general_role, commander_in_chief_role + +[roles] +corporal_role = indexer=info->action=read, \ + indexer=info->action=write +sergeant_role = indexer=info->action=write +general_role = indexer=info->action=* +commander_in_chief_role = indexer=* http://git-wip-us.apache.org/repos/asf/sentry/blob/5a7b0764/sentry-provider/sentry-provider-db/src/test/resources/indexer_invalid.ini ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/resources/indexer_invalid.ini b/sentry-provider/sentry-provider-db/src/test/resources/indexer_invalid.ini new file mode 100644 index 0000000..03083a7 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/resources/indexer_invalid.ini @@ -0,0 +1,21 @@ +# 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. + +[groups] + +[roles] +
