SENTRY-2012 - Make SentryShellGeneric extendible. Mano Kovacs, reviewed by Colm O hEigeartaigh.
Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/2314e465 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/2314e465 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/2314e465 Branch: refs/heads/master Commit: 2314e465496114444d83cec7dced60f482670179 Parents: 24d8243 Author: Colm O hEigeartaigh <[email protected]> Authored: Fri Nov 17 10:36:27 2017 +0000 Committer: Colm O hEigeartaigh <[email protected]> Committed: Fri Nov 17 10:36:27 2017 +0000 ---------------------------------------------------------------------- bin/sentryShell | 6 +- .../common/AbstractAuthorizableFactory.java | 72 ++++++ .../sentry/core/common/AuthorizableFactory.java | 50 +++++ .../sentry/core/common/AuthorizableType.java | 21 ++ .../core/model/kafka/KafkaAuthorizable.java | 2 +- .../model/kafka/KafkaModelAuthorizables.java | 27 +-- .../core/model/solr/SolrModelAuthorizable.java | 6 +- .../core/model/solr/SolrModelAuthorizables.java | 52 ++--- .../core/model/sqoop/SqoopAuthorizable.java | 2 +- .../model/sqoop/SqoopModelAuthorizables.java | 50 ++--- .../tools/GenericPrivilegeConverter.java | 96 ++++---- .../db/generic/tools/SentryConfigToolSolr.java | 9 +- .../db/generic/tools/SentryShellGeneric.java | 51 ++--- .../db/generic/tools/SentryShellKafka.java | 71 ++++++ .../db/generic/tools/SentryShellSolr.java | 52 +++++ .../db/generic/tools/SentryShellSqoop.java | 52 +++++ .../generic/tools/TestSentryConfigToolSolr.java | 9 +- .../db/generic/tools/TestSentryShellKafka.java | 207 ++++++++--------- .../db/generic/tools/TestSentryShellSolr.java | 224 +++++++++---------- .../db/generic/tools/TestSentryShellSqoop.java | 164 +++++++------- 20 files changed, 750 insertions(+), 473 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/bin/sentryShell ---------------------------------------------------------------------- diff --git a/bin/sentryShell b/bin/sentryShell index 17b1429..d7a53b8 100755 --- a/bin/sentryShell +++ b/bin/sentryShell @@ -60,9 +60,9 @@ while [ $# -gt 0 ]; do # Until you run out of parameters . . . if [[ "$1" = "-t" || "$1" = "--type" ]]; then case $2 in "hive") shell=org.apache.sentry.provider.db.tools.SentryShellHive ;; - "kafka") shell=org.apache.sentry.provider.db.generic.tools.SentryShellGeneric ;; - "solr") shell=org.apache.sentry.provider.db.generic.tools.SentryShellGeneric ;; - "sqoop") shell=org.apache.sentry.provider.db.generic.tools.SentryShellGeneric ;; + "kafka") shell=org.apache.sentry.provider.db.generic.tools.SentryShellKafka ;; + "solr") shell=org.apache.sentry.provider.db.generic.tools.SentryShellSolr ;; + "sqoop") shell=org.apache.sentry.provider.db.generic.tools.SentryShellSqoop;; *) echo "Doesn't support the type $2!"; exit 1 ;; esac fi http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AbstractAuthorizableFactory.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AbstractAuthorizableFactory.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AbstractAuthorizableFactory.java new file mode 100644 index 0000000..14bf2df --- /dev/null +++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AbstractAuthorizableFactory.java @@ -0,0 +1,72 @@ +/* + * 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 com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import org.apache.sentry.core.common.utils.SentryConstants; + +import java.util.List; + +/** + * @param <A> The type of Authorizable the class handles + */ +public abstract class AbstractAuthorizableFactory<A extends Authorizable, T extends AuthorizableType<A>> implements AuthorizableFactory<A, T> { + + @Override + public A create(String s) { + List<String> kvList = Lists.newArrayList(SentryConstants.KV_SPLITTER.trimResults().limit(2).split(s)); + if (kvList.size() != 2) { + throw new IllegalArgumentException("Invalid authorizable string value: " + s + " " + kvList); + } + + String type; + String name; + + type = kvList.get(0); + Preconditions.checkArgument(!type.isEmpty(), "Type cannot be empty"); + name = kvList.get(1); + Preconditions.checkArgument(!name.isEmpty(), "Name cannot be empty"); + try { + return create(type, name); + } catch (IllegalArgumentException e) { + return null; + } + } + + @Override + public A create(String type, String name) { + T typeObject = getType(type); + if (typeObject == null) { + return null; + } else { + return create(typeObject, name); + } + } + + private T getType(String typeName) { + for (T type : getTypes()) { + if (typeName.equalsIgnoreCase(type.name())) { + return type; + } + } + return null; + } + + protected abstract T[] getTypes(); + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableFactory.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableFactory.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableFactory.java new file mode 100644 index 0000000..9d3b5e0 --- /dev/null +++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableFactory.java @@ -0,0 +1,50 @@ +/* + * 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 javax.annotation.Nullable; + +/** + * Interface for factory class for creating authorizable objects from strings or type-name pairs. + * + * @param <A> Type of the Authorizable the implementation handles + */ +public interface AuthorizableFactory<A extends Authorizable, T extends AuthorizableType<A>> { + /** + * Parses authorizable and returns it. If s is unknown authorizable, it returns null. + * @param s type=name format of authorizable + * @return + */ + @Nullable + A create(String s); + + /** + * Returns authorizable based on type and name + * @param type + * @param name + * @return + */ + A create(String type, String name); + + /** + * Returns authorizable based on type and name + * @param type + * @param name + * @return + */ + A create(T type, String name); +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableType.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableType.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableType.java new file mode 100644 index 0000000..71cc6dd --- /dev/null +++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/AuthorizableType.java @@ -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. + */ +package org.apache.sentry.core.common; + +public interface AuthorizableType<T extends Authorizable> { + String name(); +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaAuthorizable.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaAuthorizable.java b/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaAuthorizable.java index 52ae614..269572c 100644 --- a/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaAuthorizable.java +++ b/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaAuthorizable.java @@ -44,7 +44,7 @@ public interface KafkaAuthorizable extends Authorizable { /** * Types of resources that Kafka supports authorization on. */ - public enum AuthorizableType { + enum AuthorizableType implements org.apache.sentry.core.common.AuthorizableType<KafkaAuthorizable>{ CLUSTER, HOST, TOPIC, http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaModelAuthorizables.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaModelAuthorizables.java b/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaModelAuthorizables.java index 45a1148..57a4e20 100644 --- a/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaModelAuthorizables.java +++ b/sentry-core/sentry-core-model-kafka/src/main/java/org/apache/sentry/core/model/kafka/KafkaModelAuthorizables.java @@ -16,27 +16,19 @@ */ package org.apache.sentry.core.model.kafka; -import org.apache.sentry.core.common.utils.KeyValue; -import org.apache.sentry.core.model.kafka.KafkaAuthorizable.AuthorizableType; +import org.apache.sentry.core.common.AbstractAuthorizableFactory; import org.apache.shiro.config.ConfigurationException; -public class KafkaModelAuthorizables { - public static KafkaAuthorizable from(KeyValue keyValue) throws ConfigurationException { - String prefix = keyValue.getKey().toLowerCase(); - String name = keyValue.getValue(); - for (AuthorizableType type : AuthorizableType.values()) { - if (prefix.equalsIgnoreCase(type.name())) { - return from(type, name); - } - } - return null; - } +public class KafkaModelAuthorizables extends AbstractAuthorizableFactory<KafkaAuthorizable, KafkaAuthorizable.AuthorizableType> { + private static final KafkaModelAuthorizables instance = new KafkaModelAuthorizables(); + public static KafkaAuthorizable from(String keyValue) throws ConfigurationException { - return from(new KeyValue(keyValue)); + return instance.create(keyValue); } - public static KafkaAuthorizable from(AuthorizableType type, String name) throws ConfigurationException { + @Override + public KafkaAuthorizable create(KafkaAuthorizable.AuthorizableType type, String name) throws ConfigurationException { switch (type) { case HOST: return new Host(name); @@ -54,4 +46,9 @@ public class KafkaModelAuthorizables { return null; } } + + @Override + protected KafkaAuthorizable.AuthorizableType[] getTypes() { + return KafkaAuthorizable.AuthorizableType.values(); + } } http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizable.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizable.java b/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizable.java index 56cb4c2..9eb10c3 100644 --- a/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizable.java +++ b/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizable.java @@ -22,13 +22,15 @@ import com.google.common.annotations.VisibleForTesting; public abstract class SolrModelAuthorizable implements Authorizable { - public enum AuthorizableType { + public enum AuthorizableType implements org.apache.sentry.core.common.AuthorizableType<SolrModelAuthorizable> { Collection, Field, Admin, Config, Schema - }; + } + + ; private final AuthorizableType type; private final String name; http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizables.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizables.java b/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizables.java index 7979b33..09255e7 100644 --- a/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizables.java +++ b/sentry-core/sentry-core-model-solr/src/main/java/org/apache/sentry/core/model/solr/SolrModelAuthorizables.java @@ -16,43 +16,39 @@ */ package org.apache.sentry.core.model.solr; -import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.common.AbstractAuthorizableFactory; import org.apache.sentry.core.model.solr.SolrModelAuthorizable.AuthorizableType; -public class SolrModelAuthorizables { +public class SolrModelAuthorizables extends AbstractAuthorizableFactory<SolrModelAuthorizable, AuthorizableType> { + private static final SolrModelAuthorizables instance = new SolrModelAuthorizables(); - private SolrModelAuthorizables() { - // Make constructor private to avoid instantiation + public static SolrModelAuthorizable from(String s) { + return instance.create(s); } - public static SolrModelAuthorizable from(KeyValue keyValue) { - String prefix = keyValue.getKey().toLowerCase(); - String name = keyValue.getValue().toLowerCase(); + public SolrModelAuthorizable create(SolrModelAuthorizable.AuthorizableType type, String name) { SolrModelAuthorizable result = null; - for(AuthorizableType type : AuthorizableType.values()) { - if(prefix.equalsIgnoreCase(type.name())) { - switch (type) { - case Collection: - result = new Collection(name); - break; - case Admin: - result = new AdminOperation(name); - break; - case Config: - result = new Config(name); - break; - case Schema: - result = new Schema(name); - break; - default: - break; - } - } + switch (type) { + case Collection: + result = new Collection(name); + break; + case Admin: + result = new AdminOperation(name); + break; + case Config: + result = new Config(name); + break; + case Schema: + result = new Schema(name); + break; + default: + break; } return result; } - public static SolrModelAuthorizable from(String s) { - return from(new KeyValue(s)); + @Override + protected SolrModelAuthorizable.AuthorizableType[] getTypes() { + return SolrModelAuthorizable.AuthorizableType.values(); } } http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopAuthorizable.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopAuthorizable.java b/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopAuthorizable.java index 934875e..f060d27 100644 --- a/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopAuthorizable.java +++ b/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopAuthorizable.java @@ -24,7 +24,7 @@ import org.apache.sentry.core.common.Authorizable; */ public interface SqoopAuthorizable extends Authorizable { String ALL = "*"; - public enum AuthorizableType { + enum AuthorizableType implements org.apache.sentry.core.common.AuthorizableType<SqoopAuthorizable> { SERVER, CONNECTOR, LINK, http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopModelAuthorizables.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopModelAuthorizables.java b/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopModelAuthorizables.java index 3bb9a19..0227fb8 100644 --- a/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopModelAuthorizables.java +++ b/sentry-core/sentry-core-model-sqoop/src/main/java/org/apache/sentry/core/model/sqoop/SqoopModelAuthorizables.java @@ -16,42 +16,34 @@ */ package org.apache.sentry.core.model.sqoop; -import org.apache.sentry.core.model.sqoop.SqoopAuthorizable.AuthorizableType; -import org.apache.sentry.core.common.utils.KeyValue; +import org.apache.sentry.core.common.AbstractAuthorizableFactory; -public class SqoopModelAuthorizables { +public class SqoopModelAuthorizables extends AbstractAuthorizableFactory<SqoopAuthorizable, SqoopAuthorizable.AuthorizableType> { - private SqoopModelAuthorizables() { - // Make constructor private to avoid instantiation - } - - public static SqoopAuthorizable from(KeyValue keyValue) { - String prefix = keyValue.getKey().toLowerCase(); - String name = keyValue.getValue().toLowerCase(); - for (AuthorizableType type : AuthorizableType.values()) { - if(prefix.equalsIgnoreCase(type.name())) { - return from(type, name); - } - } - return null; - } + private static final SqoopModelAuthorizables instance = new SqoopModelAuthorizables(); public static SqoopAuthorizable from(String keyValue) { - return from(new KeyValue(keyValue)); + return instance.create(keyValue); } - public static SqoopAuthorizable from(AuthorizableType type, String name) { + + public SqoopAuthorizable create(SqoopAuthorizable.AuthorizableType type, String name) { switch(type) { - case SERVER: - return new Server(name); - case JOB: - return new Job(name); - case CONNECTOR: - return new Connector(name); - case LINK: - return new Link(name); - default: - return null; + case SERVER: + return new Server(name); + case JOB: + return new Job(name); + case CONNECTOR: + return new Connector(name); + case LINK: + return new Link(name); + default: + return null; } } + + @Override + protected SqoopAuthorizable.AuthorizableType[] getTypes() { + return SqoopAuthorizable.AuthorizableType.values(); + } } http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/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..e6fa763 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 @@ -18,37 +18,25 @@ package org.apache.sentry.provider.db.generic.tools; -import static org.apache.sentry.core.common.utils.SentryConstants.AUTHORIZABLE_SEPARATOR; -import static org.apache.sentry.core.common.utils.SentryConstants.KV_SEPARATOR; -import static org.apache.sentry.core.common.utils.SentryConstants.RESOURCE_WILDCARD_VALUE; - +import com.google.common.base.Function; import com.google.common.collect.Lists; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.common.AuthorizableFactory; import org.apache.sentry.core.common.exception.SentryUserException; import org.apache.sentry.core.common.utils.KeyValue; 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.kafka.KafkaAuthorizable; -import org.apache.sentry.core.model.kafka.KafkaModelAuthorizables; -import org.apache.sentry.core.model.kafka.KafkaPrivilegeModel; -import org.apache.sentry.core.model.solr.SolrModelAuthorizables; -import org.apache.sentry.core.model.solr.SolrPrivilegeModel; -import org.apache.sentry.core.model.sqoop.SqoopModelAuthorizables; -import org.apache.sentry.core.model.sqoop.SqoopPrivilegeModel; -import org.apache.sentry.provider.common.AuthorizationComponent; import org.apache.sentry.provider.db.generic.service.thrift.TAuthorizable; import org.apache.sentry.provider.db.generic.service.thrift.TSentryGrantOption; import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; import org.apache.sentry.provider.db.generic.tools.command.TSentryPrivilegeConverter; import org.apache.shiro.config.ConfigurationException; +import java.util.ArrayList; +import java.util.List; + /** * A TSentryPrivilegeConverter implementation for "Generic" privileges, covering Apache Kafka, Apache Solr and Apache Sqoop. * It converts privilege Strings to TSentryPrivilege Objects, and vice versa, for Generic clients. @@ -61,16 +49,24 @@ public class GenericPrivilegeConverter implements TSentryPrivilegeConverter { private String service; private boolean validate; - public GenericPrivilegeConverter(String component, String service) { - this(component, service, true); - } + private List<PrivilegeValidator> privilegeValidators; + + private AuthorizableFactory authorizableFactory; + + /** + * Optional function to parse or convert privilege string. + */ + private Function<String, String> privilegeStrParser; - public GenericPrivilegeConverter(String component, String service, boolean validate) { + public GenericPrivilegeConverter(String component, String service, List<PrivilegeValidator> privilegeValidators, AuthorizableFactory authorizableFactory, boolean validate) { this.component = component; this.service = service; + this.privilegeValidators = privilegeValidators; + this.authorizableFactory = authorizableFactory; this.validate = validate; } + public TSentryPrivilege fromString(String privilegeStr) throws SentryUserException { privilegeStr = parsePrivilegeString(privilegeStr); if (validate) { @@ -78,13 +74,13 @@ public class GenericPrivilegeConverter implements TSentryPrivilegeConverter { } TSentryPrivilege tSentryPrivilege = new TSentryPrivilege(); - List<TAuthorizable> authorizables = new LinkedList<TAuthorizable>(); + List<TAuthorizable> authorizables = new ArrayList<>(); for (String authorizable : SentryConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) { KeyValue keyValue = new KeyValue(authorizable); String key = keyValue.getKey(); String value = keyValue.getValue(); - Authorizable authz = getAuthorizable(keyValue); + Authorizable authz = authorizableFactory.create(key, value); if (authz != null) { authorizables.add(new TAuthorizable(authz.getTypeName(), authz.getName())); } else if (PolicyFileConstants.PRIVILEGE_ACTION_NAME.equalsIgnoreCase(key)) { @@ -111,39 +107,30 @@ public class GenericPrivilegeConverter implements TSentryPrivilegeConverter { String grantOption = (tSentryPrivilege.getGrantOption() == TSentryGrantOption.TRUE ? "true" : "false"); - Iterator<TAuthorizable> it = authorizables.iterator(); - if (it != null) { - while (it.hasNext()) { - TAuthorizable tAuthorizable = it.next(); - privileges.add(SentryConstants.KV_JOINER.join( - tAuthorizable.getType(), tAuthorizable.getName())); - } + for (TAuthorizable tAuthorizable : authorizables) { + privileges.add(SentryConstants.KV_JOINER.join( + tAuthorizable.getType(), tAuthorizable.getName())); } if (!authorizables.isEmpty()) { privileges.add(SentryConstants.KV_JOINER.join( - PolicyFileConstants.PRIVILEGE_ACTION_NAME, action)); + PolicyFileConstants.PRIVILEGE_ACTION_NAME, action)); } // only append the grant option to privilege string if it's true if ("true".equals(grantOption)) { privileges.add(SentryConstants.KV_JOINER.join( - PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption)); + PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption)); } } return SentryConstants.AUTHORIZABLE_JOINER.join(privileges); } private String parsePrivilegeString(String privilegeStr) { - if (AuthorizationComponent.KAFKA.equals(component)) { - final String hostPrefix = KafkaAuthorizable.AuthorizableType.HOST.name() + KV_SEPARATOR; - final String hostPrefixLowerCase = hostPrefix.toLowerCase(); - if (!privilegeStr.toLowerCase().startsWith(hostPrefixLowerCase)) { - return hostPrefix + RESOURCE_WILDCARD_VALUE + AUTHORIZABLE_SEPARATOR + privilegeStr; - } + if (privilegeStrParser == null) { + return privilegeStr; } - - return privilegeStr; + return privilegeStrParser.apply(privilegeStr); } private void validatePrivilegeHierarchy(String privilegeStr) throws SentryUserException { @@ -158,28 +145,21 @@ public class GenericPrivilegeConverter implements TSentryPrivilegeConverter { } } - private 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); - } + private List<PrivilegeValidator> getPrivilegeValidators() { + return privilegeValidators; + } + - throw new SentryUserException("Invalid component specified for GenericPrivilegeCoverter: " + component); + public void setPrivilegeValidators(List<PrivilegeValidator> privilegeValidators) { + this.privilegeValidators = privilegeValidators; } - private 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); - } + public void setAuthorizableFactory(AuthorizableFactory authorizableFactory) { + this.authorizableFactory = authorizableFactory; + } - throw new SentryUserException("Invalid component specified for GenericPrivilegeCoverter: " + component); + public void setPrivilegeStrParser(Function<String, String> privilegeStrParser) { + this.privilegeStrParser = privilegeStrParser; } } http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java index 5649f43..10b875d 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java @@ -18,6 +18,7 @@ package org.apache.sentry.provider.db.generic.tools; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.collect.Table; @@ -29,6 +30,8 @@ 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.common.utils.SentryConstants; +import org.apache.sentry.core.common.validator.PrivilegeValidator; +import org.apache.sentry.core.model.solr.SolrModelAuthorizables; import org.apache.sentry.core.model.solr.SolrPrivilegeModel; import org.apache.sentry.provider.common.ProviderBackend; import org.apache.sentry.provider.common.ProviderBackendContext; @@ -92,7 +95,8 @@ public class SentryConfigToolSolr extends SentryConfigToolCommon { SimpleFileProviderBackend policyFileBackend = new SimpleFileProviderBackend(conf, policyFile); ProviderBackendContext context = new ProviderBackendContext(); - context.setValidators(SolrPrivilegeModel.getInstance().getPrivilegeValidators()); + ImmutableList<PrivilegeValidator> privilegeValidators = SolrPrivilegeModel.getInstance().getPrivilegeValidators(); + context.setValidators(privilegeValidators); policyFileBackend.initialize(context); if (validate) { validatePolicy(policyFileBackend); @@ -106,7 +110,8 @@ public class SentryConfigToolSolr extends SentryConfigToolCommon { Set<String> roles = Sets.newHashSet(); Table<String, String, Set<String>> groupRolePrivilegeTable = policyFileBackend.getGroupRolePrivilegeTable(); - GenericPrivilegeConverter converter = new GenericPrivilegeConverter(component, service, false); + SolrModelAuthorizables authorizableFactory = new SolrModelAuthorizables(); + GenericPrivilegeConverter converter = new GenericPrivilegeConverter(component, service, privilegeValidators, authorizableFactory, false); for (String groupName : groupRolePrivilegeTable.rowKeySet()) { for (String roleName : groupRolePrivilegeTable.columnKeySet()) { http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/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..8dc04f3 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 @@ -25,12 +25,11 @@ import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; -import org.apache.sentry.provider.common.AuthorizationComponent; 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.db.generic.tools.command.GenericShellCommand; -import org.apache.sentry.provider.db.generic.tools.command.TSentryPrivilegeConverter; import org.apache.sentry.provider.db.tools.SentryShellCommon; +import org.apache.sentry.service.thrift.ServiceConstants; import org.apache.sentry.provider.db.tools.ShellCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,25 +42,26 @@ import com.google.common.collect.Sets; * create role, drop role, add group to role, grant privilege to role, * revoke privilege from role, list roles, list privilege for role. */ -public class SentryShellGeneric extends SentryShellCommon { +abstract public class SentryShellGeneric extends SentryShellCommon { private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellGeneric.class); - private static final String KAFKA_SERVICE_NAME = "sentry.service.client.kafka.service.name"; - private static final String SOLR_SERVICE_NAME = "sentry.service.client.solr.service.name"; - private static final String SQOOP_SERVICE_NAME = "sentry.service.client.sqoop.service.name"; + + abstract protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service); + + abstract protected String getComponent(Configuration conf); @Override public void run() throws Exception { - String component = getComponent(); Configuration conf = getSentryConf(); - String service = getService(conf); + String component = getComponent(conf); + String service = getServiceName(conf); + try (SentryGenericServiceClient client = - SentryGenericServiceClientFactory.create(conf)) { + SentryGenericServiceClientFactory.create(conf)) { UserGroupInformation ugi = UserGroupInformation.getLoginUser(); String requestorName = ugi.getShortUserName(); - TSentryPrivilegeConverter converter = new GenericPrivilegeConverter(component, service); - ShellCommand command = new GenericShellCommand(client, component, service, converter); + ShellCommand command = new GenericShellCommand(client, component, service, getPrivilegeConverter(component, service)); // check the requestor name if (StringUtils.isEmpty(requestorName)) { @@ -102,28 +102,12 @@ public class SentryShellGeneric extends SentryShellCommon { } } - private String getComponent() throws Exception { - if (type == TYPE.kafka) { - return AuthorizationComponent.KAFKA; - } else if (type == TYPE.solr) { - return "SOLR"; - } else if (type == TYPE.sqoop) { - return AuthorizationComponent.SQOOP; - } - - throw new Exception("Invalid type specified for SentryShellGeneric: " + type); + protected String getServiceName(Configuration conf) { + return getServiceNameGeneric(conf); } - private String getService(Configuration conf) throws Exception { - if (type == TYPE.kafka) { - return conf.get(KAFKA_SERVICE_NAME, AuthorizationComponent.KAFKA); - } else if (type == TYPE.solr) { - return conf.get(SOLR_SERVICE_NAME, "service1"); - } else if (type == TYPE.sqoop) { - return conf.get(SQOOP_SERVICE_NAME, "sqoopServer1"); - } - - throw new Exception("Invalid type specified for SentryShellGeneric: " + type); + protected String getServiceNameGeneric(Configuration conf) { + return conf.get(ServiceConstants.ClientConfig.SERVICE_NAME); } private Configuration getSentryConf() { @@ -132,10 +116,9 @@ public class SentryShellGeneric extends SentryShellCommon { return conf; } - public static void main(String[] args) throws Exception { - SentryShellGeneric sentryShell = new SentryShellGeneric(); + protected void doMain(String[] args) throws Exception { try { - sentryShell.executeShell(args); + executeShell(args); } catch (Exception e) { LOGGER.error(e.getMessage(), e); Throwable current = e; http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java new file mode 100644 index 0000000..225c2e3 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java @@ -0,0 +1,71 @@ +/** + * 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.base.Function; +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.core.model.kafka.KafkaAuthorizable; +import org.apache.sentry.core.model.kafka.KafkaModelAuthorizables; +import org.apache.sentry.core.model.kafka.KafkaPrivilegeModel; +import org.apache.sentry.provider.common.AuthorizationComponent; + +import javax.annotation.Nullable; + +import static org.apache.sentry.core.common.utils.SentryConstants.*; + +public class SentryShellKafka extends SentryShellGeneric { + private static final String KAFKA_SERVICE_NAME = "sentry.service.client.kafka.service.name"; + + @Override + protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service) { + GenericPrivilegeConverter privilegeConverter = new GenericPrivilegeConverter( + component, + service, + KafkaPrivilegeModel.getInstance().getPrivilegeValidators(), + new KafkaModelAuthorizables(), + true + ); + privilegeConverter.setPrivilegeStrParser(new Function<String, String>() { + @Nullable + @Override + public String apply(@Nullable String privilegeStr) { + final String hostPrefix = KafkaAuthorizable.AuthorizableType.HOST.name() + KV_SEPARATOR; + final String hostPrefixLowerCase = hostPrefix.toLowerCase(); + if (!privilegeStr.toLowerCase().startsWith(hostPrefixLowerCase)) { + return hostPrefix + RESOURCE_WILDCARD_VALUE + AUTHORIZABLE_SEPARATOR + privilegeStr; + } + return privilegeStr; + } + }); + return privilegeConverter; + } + + @Override + protected String getComponent(Configuration conf) { + return AuthorizationComponent.KAFKA; + } + + @Override + protected String getServiceName(Configuration conf) { + return conf.get(KAFKA_SERVICE_NAME, AuthorizationComponent.KAFKA); + } + + public static void main(String[] args) throws Exception { + new SentryShellKafka().doMain(args); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java new file mode 100644 index 0000000..de37e42 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java @@ -0,0 +1,52 @@ +/** + * 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 org.apache.hadoop.conf.Configuration; +import org.apache.sentry.core.model.solr.SolrModelAuthorizables; +import org.apache.sentry.core.model.solr.SolrPrivilegeModel; +import org.apache.sentry.provider.common.AuthorizationComponent; + +public class SentryShellSolr extends SentryShellGeneric { + private static final String SOLR_SERVICE_NAME = "sentry.service.client.solr.service.name"; + + @Override + protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service) { + return new GenericPrivilegeConverter( + component, + service, + SolrPrivilegeModel.getInstance().getPrivilegeValidators(), + new SolrModelAuthorizables(), + true + ); + } + + @Override + protected String getComponent(Configuration conf) { + return AuthorizationComponent.Search; + } + + @Override + protected String getServiceName(Configuration conf) { + return conf.get(SOLR_SERVICE_NAME, "service1"); + } + + public static void main(String[] args) throws Exception { + new SentryShellSolr().doMain(args); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSqoop.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSqoop.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSqoop.java new file mode 100644 index 0000000..6315bb5 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSqoop.java @@ -0,0 +1,52 @@ +/** + * 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 org.apache.hadoop.conf.Configuration; +import org.apache.sentry.core.model.sqoop.SqoopModelAuthorizables; +import org.apache.sentry.core.model.sqoop.SqoopPrivilegeModel; +import org.apache.sentry.provider.common.AuthorizationComponent; + +public class SentryShellSqoop extends SentryShellGeneric { + private static final String SQOOP_SERVICE_NAME = "sentry.service.client.sqoop.service.name"; + + @Override + protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service) { + return new GenericPrivilegeConverter( + component, + service, + SqoopPrivilegeModel.getInstance().getPrivilegeValidators(service), + new SqoopModelAuthorizables(), + true + ); + } + + @Override + protected String getComponent(Configuration conf) { + return AuthorizationComponent.SQOOP; + } + + @Override + protected String getServiceName(Configuration conf) { + return conf.get(SQOOP_SERVICE_NAME, "sqoopServer1"); + } + + public static void main(String[] args) throws Exception { + new SentryShellSqoop().doMain(args); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolSolr.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolSolr.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolSolr.java index 9e6ff42..4a94776 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolSolr.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryConfigToolSolr.java @@ -33,6 +33,8 @@ import java.util.Map; import java.util.Set; import org.apache.commons.io.FileUtils; +import org.apache.sentry.core.model.solr.SolrModelAuthorizables; +import org.apache.sentry.core.model.solr.SolrPrivilegeModel; import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceIntegrationBase; import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole; import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; @@ -133,7 +135,12 @@ public class TestSentryConfigToolSolr extends SentryGenericServiceIntegrationBas } // check privileges - GenericPrivilegeConverter convert = new GenericPrivilegeConverter(SOLR, service); + GenericPrivilegeConverter convert = new GenericPrivilegeConverter( + SOLR, + service, + SolrPrivilegeModel.getInstance().getPrivilegeValidators(), + new SolrModelAuthorizables(), + true); for (String role : roles) { Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName( requestorName, role, SOLR, service); http://git-wip-us.apache.org/repos/asf/sentry/blob/2314e465/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java index a9234fa..fc1d1ac 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java @@ -79,32 +79,32 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { @Override public void runTestAsSubject() throws Exception { // test: create role with -cr - String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // test: create role with --create_role args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // validate the result, list roles with -lr - args = new String[] { "-lr", "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() }; + SentryShellKafka sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // test: drop role with --drop_role args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // validate the result Set<TSentryRole> roles = client.listAllRoles(requestorName, KAFKA); @@ -128,41 +128,41 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { client.createRole(requestorName, TEST_ROLE_NAME_2, KAFKA); // test: add role to group with -arg String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + confPath.getAbsolutePath() }; + SentryShellKafka.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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + "-conf", + confPath.getAbsolutePath() }; + SentryShellKafka.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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + "-conf", + confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // validate the result list roles with -lr and -g - args = new String[] { "-lr", "-g", TEST_GROUP_1, "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + args = new String[] { "-lr", "-g", TEST_GROUP_1, "-conf", confPath.getAbsolutePath() }; + SentryShellKafka sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); roleNames = getShellResultWithOSRedirect(sentryShell, args, true); validateRoleNames(roleNames, TEST_ROLE_NAME_1); args = new String[] { "--list_role", "-g", TEST_GROUP_3, "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); roleNames = getShellResultWithOSRedirect(sentryShell, args, true); validateRoleNames(roleNames, TEST_ROLE_NAME_1); // List the groups and roles via listGroups - args = new String[] { "--list_group", "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "--list_group", "-conf", confPath.getAbsolutePath()}; + sentryShell = new SentryShellKafka(); Set<String> groups = getShellResultWithOSRedirect(sentryShell, args, true); assertEquals(3, groups.size()); assertTrue(groups.contains("testGroup3 = testrole1")); @@ -171,17 +171,17 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { // test: delete role from group with -drg args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + confPath.getAbsolutePath() }; + SentryShellKafka.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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + "-conf", + confPath.getAbsolutePath() }; + SentryShellKafka.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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + "-conf", confPath.getAbsolutePath() }; + SentryShellKafka.main(args); // validate the result Set<TSentryRole> roles = client.listRolesByGroupName(requestorName, TEST_GROUP_1, KAFKA); @@ -207,17 +207,17 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA); // add role to a group (lower case) String[] args = {"-arg", "-r", TEST_ROLE_NAME_1, "-g", "group1", "-conf", - confPath.getAbsolutePath(), "-t", "kafka"}; - SentryShellGeneric.main(args); + confPath.getAbsolutePath()}; + SentryShellKafka.main(args); // validate the roles when group name is same case as above - args = new String[]{"-lr", "-g", "group1", "-conf", confPath.getAbsolutePath(), "-t", "kafka"}; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + args = new String[]{"-lr", "-g", "group1", "-conf", confPath.getAbsolutePath()}; + SentryShellKafka sentryShell = new SentryShellKafka(); 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(), "-t", "kafka"}; + args = new String[]{"-lr", "-g", "GROUP1", "-conf", confPath.getAbsolutePath()}; roleNames = getShellResultWithOSRedirect(sentryShell, args, true); validateRoleNames(roleNames); } @@ -245,23 +245,23 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { client.createRole(requestorName, TEST_ROLE_NAME_2, KAFKA); String [] privs = { - "HOST=*->CLUSTER=kafka-cluster->action=read", - "HOST=h1->TOPIC=t1->action=write", - "HOST=*->CONSUMERGROUP=cg1->action=read", - "CLUSTER=kafka-cluster->action=write", - "CONSUMERGROUP=cg2->action=write" + "HOST=*->CLUSTER=kafka-cluster->action=read", + "HOST=h1->TOPIC=t1->action=write", + "HOST=*->CONSUMERGROUP=cg1->action=read", + "CLUSTER=kafka-cluster->action=write", + "CONSUMERGROUP=cg2->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(), "-t", "kafka" }; - SentryShellGeneric.main(args); + privs[ i ], + "-conf", confPath.getAbsolutePath()}; + SentryShellKafka.main(args); } // test the list privilege - String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath()}; + SentryShellKafka sentryShell = new SentryShellKafka(); Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true); assertEquals("Incorrect number of privileges", privs.length, privilegeStrs.size()); @@ -272,8 +272,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { for (int i = 0; i < privs.length; ++i) { args = new String[] { revoke(shortOption), "-r", TEST_ROLE_NAME_1, "-p", privs[ i ], "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric.main(args); + confPath.getAbsolutePath() }; + SentryShellKafka.main(args); Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1, KAFKA, service); assertEquals("Incorrect number of privileges. Received privileges: " + Arrays.toString(privileges.toArray()), privs.length - (i + 1), privileges.size()); @@ -305,8 +305,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { public void runTestAsSubject() throws Exception { client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA); // test: create duplicate role with -cr - String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellKafka sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for creating duplicate role"); @@ -317,8 +317,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { } // test: drop non-exist role with -dr - args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for dropping non-exist role"); @@ -330,8 +330,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { // test: add non-exist role to group with -arg args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for granting non-exist role to group"); @@ -343,8 +343,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { // test: drop group from non-exist role with -drg args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for drop group from non-exist role"); @@ -356,8 +356,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { // test: grant privilege to role with the error privilege format args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", "serverserver1->action=all", - "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for the error privilege format, invalid key value."); @@ -369,16 +369,17 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { // test: grant privilege to role with the error privilege hierarchy args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", - "consumergroup=cg1->host=h1->action=create", "-conf", - confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + "consumergroup=cg1->host=h1->action=create", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); try { sentryShell.executeShell(args); fail("Exception should be thrown for the error privilege format, invalid key value."); } catch (IllegalArgumentException e) { // expected exception } catch (Exception e) { - fail ("Unexpected exception received. " + e); + throw e; +// fail ("Unexpected exception received. " + e); } // clear the test data @@ -395,86 +396,86 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { String strOptionConf = "conf"; client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA); // test: the conf is required argument - String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-t", "kafka" }; - SentryShellGeneric sentryShell = new SentryShellGeneric(); + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 }; + SentryShellKafka sentryShell = new SentryShellKafka(); validateMissingParameterMsg(sentryShell, args, SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + strOptionConf); // test: -r is required when create role - args = new String[] { "-cr", "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-cr", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-dr", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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", "server=server1", "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-gpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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", "host=*->topic=t1", "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); - try { + args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-p", "host=*->topic=t1" }; + sentryShell = new SentryShellKafka(); + try { getShellResultWithOSRedirect(sentryShell, args, false); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assert(("Kafka privilege must end with a valid action.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg).equals(e.getCause().getMessage())); } catch (Exception e) { - fail ("Unexpected exception received. " + e); - } + fail ("Unexpected exception received. " + e); + } // test: -r is required when revoke privilege from role - args = new String[] { "-rpr", "-p", "host=h1", "-conf", confPath.getAbsolutePath(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-rpr", "-p", "host=h1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); 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(), "-t", "kafka" }; - sentryShell = new SentryShellGeneric(); + args = new String[] {"-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellKafka(); validateMissingParameterMsgsContains(sentryShell, args, SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[", "-arg Add role to group", @@ -493,8 +494,8 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { } // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result. - private Set<String> getShellResultWithOSRedirect(SentryShellGeneric sentryShell, - String[] args, boolean expectedExecuteResult) throws Exception { + private Set<String> getShellResultWithOSRedirect(SentryShellKafka sentryShell, + String[] args, boolean expectedExecuteResult) throws Exception { PrintStream oldOut = System.out; ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); @@ -507,7 +508,7 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { 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()); + expectedRoleNames.length, roleNames.size()); Set<String> lowerCaseRoles = new HashSet<String>(); for (String role : roleNames) { lowerCaseRoles.add(role.toLowerCase()); @@ -515,19 +516,19 @@ public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase { for (String expectedRole : expectedRoleNames) { assertTrue("Expected role: " + expectedRole, - lowerCaseRoles.contains(expectedRole.toLowerCase())); + lowerCaseRoles.contains(expectedRole.toLowerCase())); } } } - private void validateMissingParameterMsg(SentryShellGeneric sentryShell, String[] args, - String expectedErrorMsg) throws Exception { + private void validateMissingParameterMsg(SentryShellKafka 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(SentryShellGeneric sentryShell, String[] args, - String ... expectedErrorMsgsContains) throws Exception { + private void validateMissingParameterMsgsContains(SentryShellKafka sentryShell, String[] args, + String ... expectedErrorMsgsContains) throws Exception { Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false); boolean foundAllMessages = false; Iterator<String> it = errorMsgs.iterator();
