Repository: incubator-sentry Updated Branches: refs/heads/master 0f0fd359b -> 8529f8e12
SENTRY-995: Simple Solr Shell (Gregory Chanan, reviewed by Colin Ma, Sravya Tirukkovalur) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/8529f8e1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/8529f8e1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/8529f8e1 Branch: refs/heads/master Commit: 8529f8e121144d715986a485abb204aa036caa19 Parents: 0f0fd35 Author: Gregory Chanan <[email protected]> Authored: Wed Jan 20 15:34:10 2016 -0800 Committer: Gregory Chanan <[email protected]> Committed: Wed Jan 27 16:49:29 2016 -0800 ---------------------------------------------------------------------- sentry-provider/sentry-provider-db/pom.xml | 4 + .../db/generic/tools/SentryShellSolr.java | 101 +++++ .../tools/SolrTSentryPrivilegeConvertor.java | 128 ++++++ .../db/generic/tools/command/Command.java | 27 ++ .../db/generic/tools/command/CreateRoleCmd.java | 39 ++ .../db/generic/tools/command/DropRoleCmd.java | 39 ++ .../tools/command/GrantPrivilegeToRoleCmd.java | 47 ++ .../tools/command/ListPrivilegesByRoleCmd.java | 54 +++ .../db/generic/tools/command/ListRolesCmd.java | 53 +++ .../command/RevokePrivilegeFromRoleCmd.java | 47 ++ .../command/TSentryPrivilegeConvertor.java | 33 ++ .../provider/db/tools/SentryShellCommon.java | 7 +- .../SentryGenericServiceIntegrationBase.java | 76 ++++ .../TestSentryGenericServiceIntegration.java | 53 +-- .../db/generic/tools/TestSentryShellSolr.java | 446 +++++++++++++++++++ 15 files changed, 1101 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/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 7514a7c..38e0924 100644 --- a/sentry-provider/sentry-provider-db/pom.xml +++ b/sentry-provider/sentry-provider-db/pom.xml @@ -100,6 +100,10 @@ limitations under the License. <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.sentry</groupId> + <artifactId>sentry-policy-search</artifactId> + </dependency> + <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-shims</artifactId> <scope>provided</scope> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/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..ec786a5 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java @@ -0,0 +1,101 @@ +/** + * 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.commons.lang.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +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.*; +import org.apache.sentry.provider.db.tools.SentryShellCommon; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * SentryShellSolr 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 SentryShellSolr extends SentryShellCommon { + + private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellSolr.class); + public static final String SOLR_SERVICE_NAME = "sentry.service.client.solr.service.name"; + + @Override + public void run() throws Exception { + Command command = null; + String requestorName = System.getProperty("user.name", ""); + String component = "SOLR"; + Configuration conf = getSentryConf(); + String service = conf.get(SOLR_SERVICE_NAME, "service1"); + SentryGenericServiceClient client = SentryGenericServiceClientFactory.create(conf); + + if (isCreateRole) { + command = new CreateRoleCmd(roleName, component); + } else if (isDropRole) { + command = new DropRoleCmd(roleName, component); + } else if (isAddRoleGroup) { + throw new UnsupportedOperationException("Add group to role not supported for Solr client"); + } else if (isDeleteRoleGroup) { + throw new UnsupportedOperationException("Delete group from role not supported for Solr client"); + } else if (isGrantPrivilegeRole) { + command = new GrantPrivilegeToRoleCmd(roleName, component, + privilegeStr, new SolrTSentryPrivilegeConvertor(component, service)); + } else if (isRevokePrivilegeRole) { + command = new RevokePrivilegeFromRoleCmd(roleName, component, + privilegeStr, new SolrTSentryPrivilegeConvertor(component, service)); + } else if (isListRole) { + command = new ListRolesCmd(groupName, component); + } else if (isListPrivilege) { + command = new ListPrivilegesByRoleCmd(roleName, component, + service, new SolrTSentryPrivilegeConvertor(component, service)); + } + + // check the requestor name + if (StringUtils.isEmpty(requestorName)) { + // The exception message will be recorded in log file. + throw new Exception("The requestor name is empty."); + } + + if (command != null) { + command.execute(client, requestorName); + } + } + + private Configuration getSentryConf() { + Configuration conf = new Configuration(); + conf.addResource(new Path(confPath)); + return conf; + } + + public static void main(String[] args) throws Exception { + SentryShellSolr sentryShell = new SentryShellSolr(); + try { + if (sentryShell.executeShell(args)) { + System.out.println("The operation completed successfully."); + } + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + System.out.println("The operation failed, please refer to log file for the root cause."); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConvertor.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConvertor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConvertor.java new file mode 100644 index 0000000..f6a4f15 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConvertor.java @@ -0,0 +1,128 @@ +/** + * 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 org.apache.sentry.core.model.search.Collection; +import org.apache.sentry.core.model.search.SearchModelAuthorizable; +import org.apache.sentry.core.model.search.SearchModelAuthorizable.AuthorizableType; +import org.apache.sentry.policy.search.SearchModelAuthorizables; +import org.apache.sentry.provider.common.KeyValue; +import org.apache.sentry.provider.common.PolicyFileConstants; +import org.apache.sentry.provider.common.ProviderConstants; +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.TSentryPrivilegeConvertor; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class SolrTSentryPrivilegeConvertor implements TSentryPrivilegeConvertor { + private String component; + private String service; + + public SolrTSentryPrivilegeConvertor(String component, String service) { + this.component = component; + this.service = service; + } + + public TSentryPrivilege fromString(String privilegeStr) throws Exception { + TSentryPrivilege tSentryPrivilege = new TSentryPrivilege(); + List<TAuthorizable> authorizables = new LinkedList<TAuthorizable>(); + for (String authorizable : ProviderConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) { + KeyValue keyValue = new KeyValue(authorizable); + String key = keyValue.getKey(); + String value = keyValue.getValue(); + + // is it an authorizable? + SearchModelAuthorizable authz = SearchModelAuthorizables.from(keyValue); + if (authz != null) { + if (authz instanceof Collection) { + Collection coll = (Collection)authz; + authorizables.add(new TAuthorizable(coll.getTypeName(), coll.getName())); + } else { + throw new IllegalArgumentException("Unknown authorizable type: " + authz.getTypeName()); + } + } else if (PolicyFileConstants.PRIVILEGE_ACTION_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setAction(value); + // Limitation: don't support grant at this time, since the existing solr use cases don't need it. + } else { + throw new IllegalArgumentException("Unknown key: " + key); + } + } + tSentryPrivilege.setComponent(component); + tSentryPrivilege.setServiceName(service); + tSentryPrivilege.setAuthorizables(authorizables); + validatePrivilegeHierarchy(tSentryPrivilege); + return tSentryPrivilege; + } + + public String toString(TSentryPrivilege tSentryPrivilege) { + List<String> privileges = Lists.newArrayList(); + if (tSentryPrivilege != null) { + List<TAuthorizable> authorizables = tSentryPrivilege.getAuthorizables(); + String action = tSentryPrivilege.getAction(); + 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(ProviderConstants.KV_JOINER.join( + tAuthorizable.getType(), tAuthorizable.getName())); + } + } + + if (!authorizables.isEmpty()) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_ACTION_NAME, action)); + } + + // only append the grant option to privilege string if it's true + if ("true".equals(grantOption)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption)); + } + } + return ProviderConstants.AUTHORIZABLE_JOINER.join(privileges); + } + + private static void validatePrivilegeHierarchy(TSentryPrivilege tSentryPrivilege) throws Exception { + boolean foundCollection = false; + Iterator<TAuthorizable> it = tSentryPrivilege.getAuthorizablesIterator(); + if (it != null) { + while (it.hasNext()) { + TAuthorizable authorizable = it.next(); + if (AuthorizableType.Collection.name().equals(authorizable.getType())) { + foundCollection = true; + break; + } + } + } + + if (!foundCollection) { + String msg = "Missing collection object in privilege"; + throw new IllegalArgumentException(msg); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java new file mode 100644 index 0000000..e824fb3 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java @@ -0,0 +1,27 @@ +/** + * 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.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; + +/** + * The interface for all admin commands, eg, CreateRoleCmd. + */ +public interface Command { + void execute(SentryGenericServiceClient client, String requestorName) throws Exception; +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java new file mode 100644 index 0000000..da60a64 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.tools.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; + +/** + * The class for admin command to create role. + */ +public class CreateRoleCmd implements Command { + + private String roleName; + private String component; + + public CreateRoleCmd(String roleName, String component) { + this.roleName = roleName; + this.component = component; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + client.createRole(requestorName, roleName, component); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java new file mode 100644 index 0000000..ac2a328 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.tools.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; + +/** + * The class for admin command to drop role. + */ +public class DropRoleCmd implements Command { + + private String roleName; + private String component; + + public DropRoleCmd(String roleName, String component) { + this.roleName = roleName; + this.component = component; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + client.dropRole(requestorName, roleName, component); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java new file mode 100644 index 0000000..5867983 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java @@ -0,0 +1,47 @@ +/** + * 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.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; + +/** + * The class for admin command to grant privilege to role. + */ +public class GrantPrivilegeToRoleCmd implements Command { + + private String roleName; + private String component; + private String privilegeStr; + private TSentryPrivilegeConvertor convertor; + + public GrantPrivilegeToRoleCmd(String roleName, String component, String privilegeStr, + TSentryPrivilegeConvertor convertor) { + this.roleName = roleName; + this.component = component; + this.privilegeStr = privilegeStr; + this.convertor = convertor; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + TSentryPrivilege privilege = convertor.fromString(privilegeStr); + client.grantPrivilege(requestorName, roleName, component, privilege); + + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java new file mode 100644 index 0000000..8420291 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.tools.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; + +import java.util.Set; + +/** + * The class for admin command to list privileges by role. + */ +public class ListPrivilegesByRoleCmd implements Command { + + private String roleName; + private String component; + private String serviceName; + private TSentryPrivilegeConvertor convertor; + + public ListPrivilegesByRoleCmd(String roleName, String component, String serviceName, + TSentryPrivilegeConvertor convertor) { + this.roleName = roleName; + this.component = component; + this.serviceName = serviceName; + this.convertor = convertor; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + Set<TSentryPrivilege> privileges = client + .listPrivilegesByRoleName(requestorName, roleName, component, serviceName); + if (privileges != null) { + for (TSentryPrivilege privilege : privileges) { + String privilegeStr = convertor.toString(privilege); + System.out.println(privilegeStr); + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java new file mode 100644 index 0000000..bad47ef --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java @@ -0,0 +1,53 @@ +/** + * 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.command; + +import org.apache.commons.lang.StringUtils; +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole; + +import java.util.Set; + +/** + * The class for admin command to list roles. + */ +public class ListRolesCmd implements Command { + + private String groupName; + private String component; + + public ListRolesCmd(String groupName, String component) { + this.groupName = groupName; + this.component = component; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + Set<TSentryRole> roles; + if (StringUtils.isEmpty(groupName)) { + roles = client.listAllRoles(requestorName, component); + } else { + throw new UnsupportedOperationException("List roles by group name not supported"); + } + if (roles != null) { + for (TSentryRole role : roles) { + System.out.println(role.getRoleName()); + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/RevokePrivilegeFromRoleCmd.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/RevokePrivilegeFromRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/RevokePrivilegeFromRoleCmd.java new file mode 100644 index 0000000..fba17e6 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/RevokePrivilegeFromRoleCmd.java @@ -0,0 +1,47 @@ +/** + * 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.command; + +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; + +/** + * The class for admin command to revoke privileges from role. + */ +public class RevokePrivilegeFromRoleCmd implements Command { + + private String roleName; + private String component; + private String privilegeStr; + private TSentryPrivilegeConvertor convertor; + + public RevokePrivilegeFromRoleCmd(String roleName, String component, String privilegeStr, + TSentryPrivilegeConvertor convertor) { + this.roleName = roleName; + this.component = component; + this.privilegeStr = privilegeStr; + this.convertor = convertor; + } + + @Override + public void execute(SentryGenericServiceClient client, String requestorName) throws Exception { + TSentryPrivilege privilege = convertor.fromString(privilegeStr); + client.revokePrivilege(requestorName, roleName, component, privilege); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/TSentryPrivilegeConvertor.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/TSentryPrivilegeConvertor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/TSentryPrivilegeConvertor.java new file mode 100644 index 0000000..f872341 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/tools/command/TSentryPrivilegeConvertor.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.tools.command; + +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; + +public interface TSentryPrivilegeConvertor { + + /** + * Convert string to privilege + */ + TSentryPrivilege fromString(String privilegeStr) throws Exception; + + /** + * Convert privilege to string + */ + String toString(TSentryPrivilege tSentryPrivilege); +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/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 b1353c5..3b2e233 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 @@ -18,6 +18,8 @@ package org.apache.sentry.provider.db.tools; +import com.google.common.annotations.VisibleForTesting; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; @@ -228,9 +230,10 @@ abstract public class SentryShellCommon { } // hive model and generic model should implement this method - abstract void run() throws Exception; + public abstract void run() throws Exception; - protected boolean executeShell(String[] args) throws Exception { + @VisibleForTesting + public boolean executeShell(String[] args) throws Exception { boolean result = true; if (parseArgs(args)) { run(); http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceIntegrationBase.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceIntegrationBase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceIntegrationBase.java new file mode 100644 index 0000000..e55f711 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceIntegrationBase.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.service.thrift; + +import java.security.PrivilegedExceptionAction; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.apache.sentry.service.thrift.SentryServiceIntegrationBase; +import org.junit.After; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SentryGenericServiceIntegrationBase extends SentryServiceIntegrationBase { + private static final Logger LOGGER = LoggerFactory.getLogger(SentryGenericServiceIntegrationBase.class); + protected static final String SOLR = "SOLR"; + protected SentryGenericServiceClient client; + + /** + * use the generic client to connect sentry service + */ + @Override + public void connectToSentryService() throws Exception { + // The client should already be logged in when running in solr + // therefore we must manually login in the integration tests + final SentryGenericServiceClientFactory clientFactory; + if (kerberos) { + this.client = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SentryGenericServiceClient>() { + @Override + public SentryGenericServiceClient run() throws Exception { + return SentryGenericServiceClientFactory.create(conf); + } + }); + } else { + this.client = SentryGenericServiceClientFactory.create(conf); + } + } + + @After + public void after() { + try { + runTestAsSubject(new TestOperation(){ + @Override + public void runTestAsSubject() throws Exception { + Set<TSentryRole> tRoles = client.listAllRoles(ADMIN_USER, SOLR); + for (TSentryRole tRole : tRoles) { + client.dropRole(ADMIN_USER, tRole.getRoleName(), SOLR); + } + if(client != null) { + client.close(); + } + } + }); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + policyFilePath.delete(); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/TestSentryGenericServiceIntegration.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/TestSentryGenericServiceIntegration.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/TestSentryGenericServiceIntegration.java index 4732ea2..7f8f916 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/TestSentryGenericServiceIntegration.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/thrift/TestSentryGenericServiceIntegration.java @@ -21,21 +21,16 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.List; import java.util.Set; -import javax.security.auth.Subject; - import org.apache.sentry.SentryUserException; import org.apache.sentry.core.common.ActiveRoleSet; import org.apache.sentry.core.common.Authorizable; import org.apache.sentry.core.model.search.Collection; import org.apache.sentry.core.model.search.Field; import org.apache.sentry.core.model.search.SearchConstants; -import org.apache.sentry.service.thrift.SentryServiceIntegrationBase; -import org.junit.After; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,53 +38,9 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -public class TestSentryGenericServiceIntegration extends SentryServiceIntegrationBase { - - private static final Logger LOGGER = LoggerFactory.getLogger(SentryServiceIntegrationBase.class); - private static final String SOLR = "SOLR"; - private SentryGenericServiceClient client; - - /** - * use the generic client to connect sentry service - */ - @Override - public void connectToSentryService() throws Exception { - // The client should already be logged in when running in solr - // therefore we must manually login in the integration tests - final SentryGenericServiceClientFactory clientFactory; - if (kerberos) { - this.client = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SentryGenericServiceClient>() { - @Override - public SentryGenericServiceClient run() throws Exception { - return SentryGenericServiceClientFactory.create(conf); - } - }); - } else { - this.client = SentryGenericServiceClientFactory.create(conf); - } - } +public class TestSentryGenericServiceIntegration extends SentryGenericServiceIntegrationBase { - @After - public void after() { - try { - runTestAsSubject(new TestOperation(){ - @Override - public void runTestAsSubject() throws Exception { - Set<TSentryRole> tRoles = client.listAllRoles(ADMIN_USER, SOLR); - for (TSentryRole tRole : tRoles) { - client.dropRole(ADMIN_USER, tRole.getRoleName(), SOLR); - } - if(client != null) { - client.close(); - } - } - }); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } finally { - policyFilePath.delete(); - } - } + private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryGenericServiceIntegration.class); @Test public void testCreateDropShowRole() throws Exception { http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/8529f8e1/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java new file mode 100644 index 0000000..354cf35 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java @@ -0,0 +1,446 @@ +/** + * 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.io.Files; +import com.google.common.collect.Sets; + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.security.PrivilegedExceptionAction; +import java.util.Set; +import javax.security.auth.Subject; + +import org.apache.commons.io.FileUtils; +import org.apache.sentry.SentryUserException; +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.service.thrift.SentryGenericServiceIntegrationBase; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole; +import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege; +import org.apache.sentry.provider.db.tools.SentryShellCommon; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestSentryShellSolr extends SentryGenericServiceIntegrationBase { + private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryShellSolr.class); + 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"); + if (confPath.createNewFile()) { + FileOutputStream to = new FileOutputStream(confPath); + conf.writeXml(to); + to.close(); + } + requestorName = 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); + } + + @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() }; + SentryShellSolr.main(args); + // test: create role with --create_role + args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf", + confPath.getAbsolutePath() }; + SentryShellSolr.main(args); + + // validate the result, list roles with -lr + args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() }; + SentryShellSolr sentryShell = new SentryShellSolr(); + Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + assertEquals("Incorrect number of roles", 2, roleNames.size()); + for (String roleName : roleNames) { + assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName) + || TEST_ROLE_NAME_2.equalsIgnoreCase(roleName)); + } + + // validate the result, list roles with --list_role + args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + roleNames = getShellResultWithOSRedirect(sentryShell, args, true); + assertEquals("Incorrect number of roles", 2, roleNames.size()); + for (String roleName : roleNames) { + assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName) + || TEST_ROLE_NAME_2.equalsIgnoreCase(roleName)); + } + + // test: drop role with -dr + args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellSolr.main(args); + // test: drop role with --drop_role + args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf", + confPath.getAbsolutePath() }; + SentryShellSolr.main(args); + + // validate the result + Set<TSentryRole> roles = client.listAllRoles(requestorName, SOLR); + assertEquals("Incorrect number of roles", 0, roles.size()); + } + }); + } + + // this is not supported, just check that all the permutations + // give a reasonable error + @Test + public void testAddDeleteRoleForGroup() throws Exception { + runTestAsSubject(new TestOperation() { + @Override + public void runTestAsSubject() throws Exception { + // test: add role to multiple groups + String[] args = new String[] { "-arg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup2,testGroup3", + "-conf", + confPath.getAbsolutePath() }; + SentryShellSolr sentryShell = new SentryShellSolr(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + // test: add role to group with --add_role_group + args = new String[] { "--add_role_group", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", + "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + args = new String[] { "-lr", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + // list roles with --list_role and -g + args = new String[] { "--list_role", "-g", "testGroup2", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + // test: delete group from role with -drg + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup1", "-conf", + confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup2,testGroup3", + "-conf", + confPath.getAbsolutePath() }; + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + // test: delete group from role with --delete_role_group + args = new String[] { "--delete_role_group", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", + "-conf", confPath.getAbsolutePath() }; + try { + getShellResultWithOSRedirect(sentryShell, args, false); + fail("Expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + } + }); + } + + 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, SOLR); + client.createRole(requestorName, TEST_ROLE_NAME_2, SOLR); + + String [] privs = { + "Collection=*->action=*", + "Collection=collection2->action=update", + "Collection=collection3->action=query", + }; + 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() }; + SentryShellSolr.main(args); + } + + // test the list privilege + String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellSolr sentryShell = new SentryShellSolr(); + 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() }; + SentryShellSolr.main(args); + Set<TSentryPrivilege> privileges = client.listPrivilegesByRoleName(requestorName, + TEST_ROLE_NAME_1, SOLR, service); + assertEquals("Incorrect number of privileges", privs.length - (i + 1), privileges.size()); + } + + // clear the test data + client.dropRole(requestorName, TEST_ROLE_NAME_1, SOLR); + client.dropRole(requestorName, TEST_ROLE_NAME_2, SOLR); + } + }); + } + + + @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, SOLR); + // test: create duplicate role with -cr + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() }; + SentryShellSolr sentryShell = new SentryShellSolr(); + 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 SentryShellSolr(); + try { + sentryShell.executeShell(args); + fail("Exception should be thrown for dropping 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 SentryShellSolr(); + 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 SentryShellSolr(); + 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, SOLR); + } + }); + } + + @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, SOLR); + // test: the conf is required argument + String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 }; + SentryShellSolr sentryShell = new SentryShellSolr(); + 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 SentryShellSolr(); + 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 SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -r is required when add group to role + args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -g is required when add group to role + args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME); + + // test: -r is required when delete group from role + args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME); + + // test: -g is required when delete group from role + args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + 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() }; + sentryShell = new SentryShellSolr(); + 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 SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE); + + // test: -r is required when revoke privilege from role + args = new String[] { "-rpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() }; + sentryShell = new SentryShellSolr(); + 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 SentryShellSolr(); + 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 SentryShellSolr(); + validateMissingParameterMsg(sentryShell, args, + SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[-arg Add group to role," + + " -cr Create role, -rpr Revoke privilege from role, -drg Delete group from role," + + " -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, SOLR); + } + }); + } + + // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result. + private Set<String> getShellResultWithOSRedirect(SentryShellSolr 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)); + Set<String> resultSet = Sets.newHashSet(outContent.toString().split("\n")); + System.setOut(oldOut); + return resultSet; + } + + private void validateMissingParameterMsg(SentryShellSolr sentryShell, String[] args, + String exceptedErrorMsg) throws Exception { + Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false); + assertTrue(errorMsgs.contains(exceptedErrorMsg)); + } +}
