You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by co...@apache.org on 2016/06/27 01:27:25 UTC
[3/6] sentry git commit: SENTRY-1288: Create sentry-service-client
module(Colin Ma, reviewed by Dapeng Sun)
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientDefaultImpl.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientDefaultImpl.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientDefaultImpl.java
new file mode 100644
index 0000000..d129c35
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientDefaultImpl.java
@@ -0,0 +1,591 @@
+/**
+ * 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.io.IOException;
+import java.net.InetSocketAddress;
+import java.security.PrivilegedExceptionAction;
+import java.util.*;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
+import org.apache.hadoop.security.SecurityUtil;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.core.common.ActiveRoleSet;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.utils.SentryConstants;
+import org.apache.sentry.service.thrift.ServiceConstants;
+import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.service.thrift.Status;
+import org.apache.sentry.service.thrift.sentry_common_serviceConstants;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.transport.TSaslClientTransport;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class SentryGenericServiceClientDefaultImpl implements SentryGenericServiceClient {
+ private final Configuration conf;
+ private final InetSocketAddress serverAddress;
+ private final boolean kerberos;
+ private final String[] serverPrincipalParts;
+ private SentryGenericPolicyService.Client client;
+ private TTransport transport;
+ private int connectionTimeout;
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(SentryGenericServiceClientDefaultImpl.class);
+ private static final String THRIFT_EXCEPTION_MESSAGE = "Thrift exception occured ";
+
+ /**
+ * This transport wraps the Sasl transports to set up the right UGI context for open().
+ */
+ public static class UgiSaslClientTransport extends TSaslClientTransport {
+ protected UserGroupInformation ugi = null;
+
+ public UgiSaslClientTransport(String mechanism, String authorizationId,
+ String protocol, String serverName, Map<String, String> props,
+ CallbackHandler cbh, TTransport transport, boolean wrapUgi, Configuration conf)
+ throws IOException {
+ super(mechanism, authorizationId, protocol, serverName, props, cbh,
+ transport);
+ if (wrapUgi) {
+ // If we don't set the configuration, the UGI will be created based on
+ // what's on the classpath, which may lack the kerberos changes we require
+ UserGroupInformation.setConfiguration(conf);
+ ugi = UserGroupInformation.getLoginUser();
+ }
+ }
+
+ // open the SASL transport with using the current UserGroupInformation
+ // This is needed to get the current login context stored
+ @Override
+ public void open() throws TTransportException {
+ if (ugi == null) {
+ baseOpen();
+ } else {
+ try {
+ if (ugi.isFromKeytab()) {
+ ugi.checkTGTAndReloginFromKeytab();
+ }
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+ public Void run() throws TTransportException {
+ baseOpen();
+ return null;
+ }
+ });
+ } catch (IOException e) {
+ throw new TTransportException("Failed to open SASL transport: " + e.getMessage(), e);
+ } catch (InterruptedException e) {
+ throw new TTransportException(
+ "Interrupted while opening underlying transport: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private void baseOpen() throws TTransportException {
+ super.open();
+ }
+ }
+
+ public SentryGenericServiceClientDefaultImpl(Configuration conf) throws IOException {
+ // copy the configuration because we may make modifications to it.
+ this.conf = new Configuration(conf);
+ Preconditions.checkNotNull(this.conf, "Configuration object cannot be null");
+ this.serverAddress = NetUtils.createSocketAddr(Preconditions.checkNotNull(
+ conf.get(ClientConfig.SERVER_RPC_ADDRESS), "Config key "
+ + ClientConfig.SERVER_RPC_ADDRESS + " is required"), conf.getInt(
+ ClientConfig.SERVER_RPC_PORT, ClientConfig.SERVER_RPC_PORT_DEFAULT));
+ this.connectionTimeout = conf.getInt(ClientConfig.SERVER_RPC_CONN_TIMEOUT,
+ ClientConfig.SERVER_RPC_CONN_TIMEOUT_DEFAULT);
+ kerberos = ServerConfig.SECURITY_MODE_KERBEROS.equalsIgnoreCase(
+ conf.get(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_KERBEROS).trim());
+ transport = new TSocket(serverAddress.getHostName(),
+ serverAddress.getPort(), connectionTimeout);
+ if (kerberos) {
+ String serverPrincipal = Preconditions.checkNotNull(conf.get(ServerConfig.PRINCIPAL), ServerConfig.PRINCIPAL + " is required");
+ // since the client uses hadoop-auth, we need to set kerberos in
+ // hadoop-auth if we plan to use kerberos
+ conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, ServerConfig.SECURITY_MODE_KERBEROS);
+
+ // Resolve server host in the same way as we are doing on server side
+ serverPrincipal = SecurityUtil.getServerPrincipal(serverPrincipal, serverAddress.getAddress());
+ LOGGER.debug("Using server kerberos principal: " + serverPrincipal);
+
+ serverPrincipalParts = SaslRpcServer.splitKerberosName(serverPrincipal);
+ Preconditions.checkArgument(serverPrincipalParts.length == 3,
+ "Kerberos principal should have 3 parts: " + serverPrincipal);
+ boolean wrapUgi = "true".equalsIgnoreCase(conf
+ .get(ServerConfig.SECURITY_USE_UGI_TRANSPORT, "true"));
+ transport = new UgiSaslClientTransport(AuthMethod.KERBEROS.getMechanismName(),
+ null, serverPrincipalParts[0], serverPrincipalParts[1],
+ ClientConfig.SASL_PROPERTIES, null, transport, wrapUgi, conf);
+ } else {
+ serverPrincipalParts = null;
+ }
+ try {
+ transport.open();
+ } catch (TTransportException e) {
+ throw new IOException("Transport exception while opening transport: " + e.getMessage(), e);
+ }
+ LOGGER.debug("Successfully opened transport: " + transport + " to " + serverAddress);
+ long maxMessageSize = conf.getLong(ServiceConstants.ClientConfig.SENTRY_POLICY_CLIENT_THRIFT_MAX_MESSAGE_SIZE,
+ ServiceConstants.ClientConfig.SENTRY_POLICY_CLIENT_THRIFT_MAX_MESSAGE_SIZE_DEFAULT);
+ TMultiplexedProtocol protocol = new TMultiplexedProtocol(
+ new TBinaryProtocol(transport, maxMessageSize, maxMessageSize, true, true),
+ ServiceConstants.SENTRY_GENERIC_SERVICE_NAME);
+ client = new SentryGenericPolicyService.Client(protocol);
+ LOGGER.debug("Successfully created client");
+ }
+
+
+
+ /**
+ * Create a sentry role
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @throws SentryUserException
+ */
+ public synchronized void createRole(String requestorUserName, String roleName, String component)
+ throws SentryUserException {
+ TCreateSentryRoleRequest request = new TCreateSentryRoleRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setComponent(component);
+ try {
+ TCreateSentryRoleResponse response = client.create_sentry_role(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ public void createRoleIfNotExist(String requestorUserName, String roleName, String component) throws SentryUserException {
+ TCreateSentryRoleRequest request = new TCreateSentryRoleRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setComponent(component);
+ try {
+ TCreateSentryRoleResponse response = client.create_sentry_role(request);
+ Status status = Status.fromCode(response.getStatus().getValue());
+ if (status == Status.ALREADY_EXISTS) {
+ return;
+ }
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * Drop a sentry role
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @throws SentryUserException
+ */
+ public void dropRole(String requestorUserName,
+ String roleName, String component)
+ throws SentryUserException {
+ dropRole(requestorUserName, roleName, component, false);
+ }
+
+ public void dropRoleIfExists(String requestorUserName,
+ String roleName, String component)
+ throws SentryUserException {
+ dropRole(requestorUserName, roleName, component, true);
+ }
+
+ private void dropRole(String requestorUserName,
+ String roleName, String component , boolean ifExists)
+ throws SentryUserException {
+ TDropSentryRoleRequest request = new TDropSentryRoleRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setComponent(component);
+ try {
+ TDropSentryRoleResponse response = client.drop_sentry_role(request);
+ Status status = Status.fromCode(response.getStatus().getValue());
+ if (ifExists && status == Status.NO_SUCH_OBJECT) {
+ return;
+ }
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * add a sentry role to groups.
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @param groups: The name of groups
+ * @throws SentryUserException
+ */
+ public void addRoleToGroups(String requestorUserName, String roleName,
+ String component, Set<String> groups) throws SentryUserException {
+ TAlterSentryRoleAddGroupsRequest request = new TAlterSentryRoleAddGroupsRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setGroups(groups);
+ request.setComponent(component);
+
+ try {
+ TAlterSentryRoleAddGroupsResponse response = client.alter_sentry_role_add_groups(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * delete a sentry role from groups.
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @param groups: The name of groups
+ * @throws SentryUserException
+ */
+ public void deleteRoleToGroups(String requestorUserName, String roleName,
+ String component, Set<String> groups) throws SentryUserException {
+ TAlterSentryRoleDeleteGroupsRequest request = new TAlterSentryRoleDeleteGroupsRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setGroups(groups);
+ request.setComponent(component);
+
+ try {
+ TAlterSentryRoleDeleteGroupsResponse response = client.alter_sentry_role_delete_groups(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * grant privilege
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @param privilege
+ * @throws SentryUserException
+ */
+ public void grantPrivilege(String requestorUserName, String roleName,
+ String component, TSentryPrivilege privilege) throws SentryUserException {
+ TAlterSentryRoleGrantPrivilegeRequest request = new TAlterSentryRoleGrantPrivilegeRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setRoleName(roleName);
+ request.setRequestorUserName(requestorUserName);
+ request.setPrivilege(privilege);
+
+ try {
+ TAlterSentryRoleGrantPrivilegeResponse response = client.alter_sentry_role_grant_privilege(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * revoke privilege
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName: Name of the role
+ * @param component: The request is issued to which component
+ * @param privilege
+ * @throws SentryUserException
+ */
+ public void revokePrivilege(String requestorUserName, String roleName,
+ String component, TSentryPrivilege privilege) throws SentryUserException {
+ TAlterSentryRoleRevokePrivilegeRequest request = new TAlterSentryRoleRevokePrivilegeRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ request.setPrivilege(privilege);
+
+ try {
+ TAlterSentryRoleRevokePrivilegeResponse response = client.alter_sentry_role_revoke_privilege(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * drop privilege
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param component: The request is issued to which component
+ * @param privilege
+ * @throws SentryUserException
+ */
+ public void dropPrivilege(String requestorUserName,String component,
+ TSentryPrivilege privilege) throws SentryUserException {
+ TDropPrivilegesRequest request = new TDropPrivilegesRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setRequestorUserName(requestorUserName);
+ request.setPrivilege(privilege);
+
+ try {
+ TDropPrivilegesResponse response = client.drop_sentry_privilege(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * rename privilege
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param component: The request is issued to which component
+ * @param serviceName: The Authorizable belongs to which service
+ * @param oldAuthorizables
+ * @param newAuthorizables
+ * @throws SentryUserException
+ */
+ public void renamePrivilege(String requestorUserName, String component,
+ String serviceName, List<? extends Authorizable> oldAuthorizables,
+ List<? extends Authorizable> newAuthorizables) throws SentryUserException {
+ if (oldAuthorizables == null || oldAuthorizables.isEmpty()
+ || newAuthorizables == null || newAuthorizables.isEmpty()) {
+ throw new SentryUserException("oldAuthorizables or newAuthorizables can not be null or empty");
+ }
+
+ TRenamePrivilegesRequest request = new TRenamePrivilegesRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setRequestorUserName(requestorUserName);
+ request.setServiceName(serviceName);
+
+ List<TAuthorizable> oldTAuthorizables = Lists.newArrayList();
+ List<TAuthorizable> newTAuthorizables = Lists.newArrayList();
+ for (Authorizable authorizable : oldAuthorizables) {
+ oldTAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+ request.setOldAuthorizables(oldTAuthorizables);
+ }
+ for (Authorizable authorizable : newAuthorizables) {
+ newTAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+ request.setNewAuthorizables(newTAuthorizables);
+ }
+
+ try {
+ TRenamePrivilegesResponse response = client.rename_sentry_privilege(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * Gets sentry role objects for a given groupName using the Sentry service
+ * @param requestorUserName : user on whose behalf the request is issued
+ * @param groupName : groupName to look up ( if null returns all roles for groups related to requestorUserName)
+ * @param component: The request is issued to which component
+ * @return Set of thrift sentry role objects
+ * @throws SentryUserException
+ */
+ public synchronized Set<TSentryRole> listRolesByGroupName(
+ String requestorUserName,
+ String groupName,
+ String component)
+ throws SentryUserException {
+ TListSentryRolesRequest request = new TListSentryRolesRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setRequestorUserName(requestorUserName);
+ request.setGroupName(groupName);
+ request.setComponent(component);
+ TListSentryRolesResponse response;
+ try {
+ response = client.list_sentry_roles_by_group(request);
+ Status.throwIfNotOk(response.getStatus());
+ return response.getRoles();
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ public Set<TSentryRole> listUserRoles(String requestorUserName, String component)
+ throws SentryUserException {
+ return listRolesByGroupName(requestorUserName, SentryConstants.RESOURCE_WILDCARD_VALUE, component);
+ }
+
+ public Set<TSentryRole> listAllRoles(String requestorUserName, String component)
+ throws SentryUserException {
+ return listRolesByGroupName(requestorUserName, null, component);
+ }
+
+ /**
+ * Gets sentry privileges for a given roleName and Authorizable Hirerchys using the Sentry service
+ * @param requestorUserName: user on whose behalf the request is issued
+ * @param roleName:
+ * @param component: The request is issued to which component
+ * @param serviceName
+ * @param authorizables
+ * @return
+ * @throws SentryUserException
+ */
+ public Set<TSentryPrivilege> listPrivilegesByRoleName(
+ String requestorUserName, String roleName, String component,
+ String serviceName, List<? extends Authorizable> authorizables)
+ throws SentryUserException {
+ TListSentryPrivilegesRequest request = new TListSentryPrivilegesRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setServiceName(serviceName);
+ request.setRequestorUserName(requestorUserName);
+ request.setRoleName(roleName);
+ if (authorizables != null && !authorizables.isEmpty()) {
+ List<TAuthorizable> tAuthorizables = Lists.newArrayList();
+ for (Authorizable authorizable : authorizables) {
+ tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+ }
+ request.setAuthorizables(tAuthorizables);
+ }
+
+ TListSentryPrivilegesResponse response;
+ try {
+ response = client.list_sentry_privileges_by_role(request);
+ Status.throwIfNotOk(response.getStatus());
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ return response.getPrivileges();
+ }
+
+ public Set<TSentryPrivilege> listPrivilegesByRoleName(
+ String requestorUserName, String roleName, String component,
+ String serviceName) throws SentryUserException {
+ return listPrivilegesByRoleName(requestorUserName, roleName, component, serviceName, null);
+ }
+
+ /**
+ * get sentry permissions from provider as followings:
+ * @param: component: The request is issued to which component
+ * @param: serviceName: The privilege belongs to which service
+ * @param: roleSet
+ * @param: groupNames
+ * @param: the authorizables
+ * @returns the set of permissions
+ * @throws SentryUserException
+ */
+ public Set<String> listPrivilegesForProvider(String component,
+ String serviceName, ActiveRoleSet roleSet, Set<String> groups,
+ List<? extends Authorizable> authorizables) throws SentryUserException {
+ TSentryActiveRoleSet thriftRoleSet = new TSentryActiveRoleSet(roleSet.isAll(), roleSet.getRoles());
+ TListSentryPrivilegesForProviderRequest request = new TListSentryPrivilegesForProviderRequest();
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setServiceName(serviceName);
+ request.setRoleSet(thriftRoleSet);
+ if (groups == null) {
+ request.setGroups(new HashSet<String>());
+ } else {
+ request.setGroups(groups);
+ }
+ List<TAuthorizable> tAuthoriables = Lists.newArrayList();
+ if (authorizables != null && !authorizables.isEmpty()) {
+ for (Authorizable authorizable : authorizables) {
+ tAuthoriables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+ }
+ request.setAuthorizables(tAuthoriables);
+ }
+
+ try {
+ TListSentryPrivilegesForProviderResponse response = client.list_sentry_privileges_for_provider(request);
+ Status.throwIfNotOk(response.getStatus());
+ return response.getPrivileges();
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ /**
+ * Get sentry privileges based on valid active roles and the authorize objects. Note that
+ * it is client responsibility to ensure the requestor username, etc. is not impersonated.
+ *
+ * @param component: The request respond to which component.
+ * @param serviceName: The name of service.
+ * @param requestorUserName: The requestor user name.
+ * @param authorizablesSet: The set of authorize objects. One authorize object is represented
+ * as a string. e.g resourceType1=resourceName1->resourceType2=resourceName2->resourceType3=resourceName3.
+ * @param groups: The requested groups.
+ * @param roleSet: The active roles set.
+ *
+ * @returns The mapping of authorize objects and TSentryPrivilegeMap(<role, set<privileges>).
+ * @throws SentryUserException
+ */
+ public Map<String, TSentryPrivilegeMap> listPrivilegsbyAuthorizable(String component,
+ String serviceName, String requestorUserName, Set<String> authorizablesSet,
+ Set<String> groups, ActiveRoleSet roleSet) throws SentryUserException {
+
+ TListSentryPrivilegesByAuthRequest request = new TListSentryPrivilegesByAuthRequest();
+
+ request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2);
+ request.setComponent(component);
+ request.setServiceName(serviceName);
+ request.setRequestorUserName(requestorUserName);
+ request.setAuthorizablesSet(authorizablesSet);
+
+ if (groups == null) {
+ request.setGroups(new HashSet<String>());
+ } else {
+ request.setGroups(groups);
+ }
+
+ if (roleSet != null) {
+ request.setRoleSet(new TSentryActiveRoleSet(roleSet.isAll(), roleSet.getRoles()));
+ }
+
+ try {
+ TListSentryPrivilegesByAuthResponse response = client.list_sentry_privileges_by_authorizable(request);
+ Status.throwIfNotOk(response.getStatus());
+ return response.getPrivilegesMapByAuth();
+ } catch (TException e) {
+ throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e);
+ }
+ }
+
+ @Override
+ public void close() {
+ if (transport != null) {
+ transport.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientFactory.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientFactory.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientFactory.java
new file mode 100644
index 0000000..980d930
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClientFactory.java
@@ -0,0 +1,34 @@
+/**
+ * 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 org.apache.hadoop.conf.Configuration;
+
+/**
+ * SentryGenericServiceClientFactory is a public class for the components which using Generic Model to create sentry client.
+ */
+public final class SentryGenericServiceClientFactory {
+
+ private SentryGenericServiceClientFactory() {
+ }
+
+ public static SentryGenericServiceClient create(Configuration conf) throws Exception {
+ return new SentryGenericServiceClientDefaultImpl(conf);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/KafkaTSentryPrivilegeConverter.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/KafkaTSentryPrivilegeConverter.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/KafkaTSentryPrivilegeConverter.java
new file mode 100644
index 0000000..688bc9e
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/KafkaTSentryPrivilegeConverter.java
@@ -0,0 +1,118 @@
+/**
+ * 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.common.utils.KeyValue;
+import org.apache.sentry.core.common.utils.SentryConstants;
+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.validator.KafkaPrivilegeValidator;
+import org.apache.sentry.core.common.utils.PolicyFileConstants;
+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 java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+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;
+
+public class KafkaTSentryPrivilegeConverter implements TSentryPrivilegeConverter {
+ private String component;
+ private String service;
+
+ public KafkaTSentryPrivilegeConverter(String component, String service) {
+ this.component = component;
+ this.service = service;
+ }
+
+ public TSentryPrivilege fromString(String privilegeStr) throws Exception {
+ final String hostPrefix = KafkaAuthorizable.AuthorizableType.HOST.name() + KV_SEPARATOR;
+ final String hostPrefixLowerCase = hostPrefix.toLowerCase();
+ if (!privilegeStr.toLowerCase().startsWith(hostPrefixLowerCase)) {
+ privilegeStr = hostPrefix + RESOURCE_WILDCARD_VALUE + AUTHORIZABLE_SEPARATOR + privilegeStr;
+ }
+ validatePrivilegeHierarchy(privilegeStr);
+ TSentryPrivilege tSentryPrivilege = new TSentryPrivilege();
+ List<TAuthorizable> authorizables = new LinkedList<TAuthorizable>();
+ for (String authorizable : SentryConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) {
+ KeyValue keyValue = new KeyValue(authorizable);
+ String key = keyValue.getKey();
+ String value = keyValue.getValue();
+
+ // is it an authorizable?
+ KafkaAuthorizable authz = KafkaModelAuthorizables.from(keyValue);
+ if (authz != null) {
+ authorizables.add(new TAuthorizable(authz.getTypeName(), authz.getName()));
+
+ } else if (PolicyFileConstants.PRIVILEGE_ACTION_NAME.equalsIgnoreCase(key)) {
+ tSentryPrivilege.setAction(value);
+ }
+ }
+
+ if (tSentryPrivilege.getAction() == null) {
+ throw new IllegalArgumentException("Privilege is invalid: action required but not specified.");
+ }
+ tSentryPrivilege.setComponent(component);
+ tSentryPrivilege.setServiceName(service);
+ tSentryPrivilege.setAuthorizables(authorizables);
+ 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(SentryConstants.KV_JOINER.join(
+ tAuthorizable.getType(), tAuthorizable.getName()));
+ }
+ }
+
+ if (!authorizables.isEmpty()) {
+ privileges.add(SentryConstants.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(SentryConstants.KV_JOINER.join(
+ PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption));
+ }
+ }
+ return SentryConstants.AUTHORIZABLE_JOINER.join(privileges);
+ }
+
+ private static void validatePrivilegeHierarchy(String privilegeStr) throws Exception {
+ new KafkaPrivilegeValidator().validate(new PrivilegeValidatorContext(privilegeStr));
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolCommon.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolCommon.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolCommon.java
new file mode 100644
index 0000000..013e824
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolCommon.java
@@ -0,0 +1,152 @@
+/**
+ * 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.annotations.VisibleForTesting;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+
+abstract public class SentryConfigToolCommon {
+ private String policyFile;
+ private boolean validate;
+ private boolean importPolicy;
+ private boolean checkCompat;
+ private String confPath;
+
+ /**
+ * parse arguments
+ * <pre>
+ * -conf,--sentry_conf <filepath> sentry config file path
+ * -p,--policy_ini <arg> policy file path
+ * -v,--validate validate policy file
+ * -c,--checkcompat check compatibility with service
+ * -i,--import import policy file
+ * -h,--help print usage
+ * </pre>
+ * @param args
+ */
+ protected boolean parseArgs(String [] args) {
+ Options options = new Options();
+
+ Option globalPolicyPath = new Option("p", "policy_ini", true,
+ "Policy file path");
+ globalPolicyPath.setRequired(true);
+ options.addOption(globalPolicyPath);
+
+ Option validateOpt = new Option("v", "validate", false,
+ "Validate policy file");
+ validateOpt.setRequired(false);
+ options.addOption(validateOpt);
+
+ Option checkCompatOpt = new Option("c","checkcompat",false,
+ "Check compatibility with Sentry Service");
+ checkCompatOpt.setRequired(false);
+ options.addOption(checkCompatOpt);
+
+ Option importOpt = new Option("i", "import", false,
+ "Import policy file");
+ importOpt.setRequired(false);
+ options.addOption(importOpt);
+
+ // file path of sentry-site
+ Option sentrySitePathOpt = new Option("conf", "sentry_conf", true, "sentry-site file path");
+ sentrySitePathOpt.setRequired(true);
+ options.addOption(sentrySitePathOpt);
+
+ // help option
+ Option helpOpt = new Option("h", "help", false, "Shell usage");
+ helpOpt.setRequired(false);
+ options.addOption(helpOpt);
+
+ // this Options is parsed first for help option
+ Options helpOptions = new Options();
+ helpOptions.addOption(helpOpt);
+
+ try {
+ Parser parser = new GnuParser();
+
+ // parse help option first
+ CommandLine cmd = parser.parse(helpOptions, args, true);
+ for (Option opt : cmd.getOptions()) {
+ if (opt.getOpt().equals("h")) {
+ // get the help option, print the usage and exit
+ usage(options);
+ return false;
+ }
+ }
+
+ // without help option
+ cmd = parser.parse(options, args);
+
+ for (Option opt : cmd.getOptions()) {
+ if (opt.getOpt().equals("p")) {
+ policyFile = opt.getValue();
+ } else if (opt.getOpt().equals("v")) {
+ validate = true;
+ } else if (opt.getOpt().equals("i")) {
+ importPolicy = true;
+ } else if (opt.getOpt().equals("c")) {
+ checkCompat = true;
+ } else if (opt.getOpt().equals("conf")) {
+ confPath = opt.getValue();
+ }
+ }
+
+ if (!validate && !importPolicy) {
+ throw new IllegalArgumentException("No action specified; at least one of action or import must be specified");
+ }
+ } catch (ParseException pe) {
+ System.out.println(pe.getMessage());
+ usage(options);
+ return false;
+ }
+ return true;
+ }
+
+ // print usage
+ private void usage(Options sentryOptions) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("sentryConfigTool", sentryOptions);
+ }
+
+ public abstract void run() throws Exception;
+
+ @VisibleForTesting
+ public boolean executeConfigTool(String [] args) throws Exception {
+ boolean result = true;
+ if (parseArgs(args)) {
+ run();
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ public String getPolicyFile() { return policyFile; }
+ public boolean getValidate() { return validate; }
+ public boolean getImportPolicy() { return importPolicy; }
+ public boolean getCheckCompat() { return checkCompat; }
+ public String getConfPath() { return confPath; }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java
new file mode 100644
index 0000000..404adb8
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryConfigToolSolr.java
@@ -0,0 +1,262 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.generic.tools;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.core.common.Action;
+import org.apache.sentry.core.common.exception.SentryConfigurationException;
+import org.apache.sentry.core.common.utils.KeyValue;
+import org.apache.sentry.core.common.utils.SentryConstants;
+import org.apache.sentry.core.model.search.SearchPrivilegeModel;
+import org.apache.sentry.provider.common.ProviderBackend;
+import org.apache.sentry.provider.common.ProviderBackendContext;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClientFactory;
+import org.apache.sentry.provider.file.SimpleFileProviderBackend;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * SentryConfigToolSolr is an administrative tool used to parse a Solr policy file
+ * and add the role, group mappings, and privileges therein to the Sentry service.
+ */
+public class SentryConfigToolSolr extends SentryConfigToolCommon {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentryConfigToolSolr.class);
+ public static final String SOLR_SERVICE_NAME = "sentry.service.client.solr.service.name";
+
+ @Override
+ public void run() throws Exception {
+ String component = "SOLR";
+ Configuration conf = getSentryConf();
+
+ String service = conf.get(SOLR_SERVICE_NAME, "service1");
+ // instantiate a solr client for sentry service. This sets the ugi, so must
+ // be done before getting the ugi below.
+ SentryGenericServiceClient client = SentryGenericServiceClientFactory.create(conf);
+ UserGroupInformation ugi = UserGroupInformation.getLoginUser();
+ String requestorName = ugi.getShortUserName();
+
+ convertINIToSentryServiceCmds(component, service, requestorName, conf, client,
+ getPolicyFile(), getValidate(), getImportPolicy(), getCheckCompat());
+ }
+
+ private Configuration getSentryConf() {
+ Configuration conf = new Configuration();
+ conf.addResource(new Path(getConfPath()));
+ return conf;
+ }
+
+ /**
+ * Convert policy file to solrctl commands -- based on SENTRY-480
+ */
+ private void convertINIToSentryServiceCmds(String component,
+ String service, String requestorName,
+ Configuration conf, SentryGenericServiceClient client,
+ String policyFile, boolean validate, boolean importPolicy,
+ boolean checkCompat) throws Exception {
+
+ //instantiate a file providerBackend for parsing
+ LOGGER.info("Reading policy file at: " + policyFile);
+ SimpleFileProviderBackend policyFileBackend =
+ new SimpleFileProviderBackend(conf, policyFile);
+ ProviderBackendContext context = new ProviderBackendContext();
+ context.setValidators(SearchPrivilegeModel.getInstance().getPrivilegeValidators());
+ policyFileBackend.initialize(context);
+ if (validate) {
+ validatePolicy(policyFileBackend);
+ }
+
+ if (checkCompat) {
+ checkCompat(policyFileBackend);
+ }
+
+ //import the relations about group,role and privilege into the DB store
+ Set<String> roles = Sets.newHashSet();
+ Table<String, String, Set<String>> groupRolePrivilegeTable =
+ policyFileBackend.getGroupRolePrivilegeTable();
+ SolrTSentryPrivilegeConverter converter = new SolrTSentryPrivilegeConverter(component, service, false);
+
+ for (String groupName : groupRolePrivilegeTable.rowKeySet()) {
+ for (String roleName : groupRolePrivilegeTable.columnKeySet()) {
+ if (!roles.contains(roleName)) {
+ LOGGER.info(dryRunMessage(importPolicy) + "Creating role: " + roleName.toLowerCase(Locale.US));
+ if (importPolicy) {
+ client.createRoleIfNotExist(requestorName, roleName, component);
+ }
+ roles.add(roleName);
+ }
+
+ Set<String> privileges = groupRolePrivilegeTable.get(groupName, roleName);
+ if (privileges == null) {
+ continue;
+ }
+ LOGGER.info(dryRunMessage(importPolicy) + "Adding role: " + roleName.toLowerCase(Locale.US) + " to group: " + groupName);
+ if (importPolicy) {
+ client.addRoleToGroups(requestorName, roleName, component, Sets.newHashSet(groupName));
+ }
+
+ for (String permission : privileges) {
+ String action = null;
+
+ for (String authorizable : SentryConstants.AUTHORIZABLE_SPLITTER.
+ trimResults().split(permission)) {
+ KeyValue kv = new KeyValue(authorizable);
+ String key = kv.getKey();
+ String value = kv.getValue();
+ if ("action".equalsIgnoreCase(key)) {
+ action = value;
+ }
+ }
+
+ // Service doesn't support not specifying action
+ if (action == null) {
+ permission += "->action=" + Action.ALL;
+ }
+ LOGGER.info(dryRunMessage(importPolicy) + "Adding permission: " + permission + " to role: " + roleName.toLowerCase(Locale.US));
+ if (importPolicy) {
+ client.grantPrivilege(requestorName, roleName, component, converter.fromString(permission));
+ }
+ }
+ }
+ }
+ }
+
+ private void validatePolicy(ProviderBackend backend) throws Exception {
+ try {
+ backend.validatePolicy(true);
+ } catch (SentryConfigurationException e) {
+ printConfigErrorsWarnings(e);
+ throw e;
+ }
+ }
+
+ private void printConfigErrorsWarnings(SentryConfigurationException configException) {
+ System.out.println(" *** Found configuration problems *** ");
+ for (String errMsg : configException.getConfigErrors()) {
+ System.out.println("ERROR: " + errMsg);
+ }
+ for (String warnMsg : configException.getConfigWarnings()) {
+ System.out.println("Warning: " + warnMsg);
+ }
+ }
+
+ private void checkCompat(SimpleFileProviderBackend backend) throws Exception {
+ Map<String, Set<String>> rolesCaseMapping = new HashMap<String, Set<String>>();
+ Table<String, String, Set<String>> groupRolePrivilegeTable =
+ backend.getGroupRolePrivilegeTable();
+
+ for (String roleName : groupRolePrivilegeTable.columnKeySet()) {
+ String roleNameLower = roleName.toLowerCase(Locale.US);
+ if (!roleName.equals(roleNameLower)) {
+ if (!rolesCaseMapping.containsKey(roleNameLower)) {
+ rolesCaseMapping.put(roleNameLower, Sets.newHashSet(roleName));
+ } else {
+ rolesCaseMapping.get(roleNameLower).add(roleName);
+ }
+ }
+ }
+
+ List<String> errors = new LinkedList<String>();
+ StringBuilder warningString = new StringBuilder();
+ if (!rolesCaseMapping.isEmpty()) {
+ warningString.append("The following roles names will be lower cased when added to the Sentry Service.\n");
+ warningString.append("This will cause document-level security to fail to match the role tokens.\n");
+ warningString.append("Role names: ");
+ }
+ boolean firstWarning = true;
+
+ for (Map.Entry<String, Set<String>> entry : rolesCaseMapping.entrySet()) {
+ Set<String> caseMapping = entry.getValue();
+ if (caseMapping.size() > 1) {
+ StringBuilder errorString = new StringBuilder();
+ errorString.append("The following (cased) roles map to the same role in the sentry service: ");
+ boolean first = true;
+ for (String casedRole : caseMapping) {
+ errorString.append(first ? "" : ", ");
+ errorString.append(casedRole);
+ first = false;
+ }
+ errorString.append(". Role in service: ").append(entry.getKey());
+ errors.add(errorString.toString());
+ }
+
+ for (String casedRole : caseMapping) {
+ warningString.append(firstWarning? "" : ", ");
+ warningString.append(casedRole);
+ firstWarning = false;
+ }
+ }
+
+ for (String error : errors) {
+ System.out.println("ERROR: " + error);
+ }
+ System.out.println("\n");
+
+ System.out.println("Warning: " + warningString.toString());
+ if (errors.size() > 0) {
+ SentryConfigurationException ex =
+ new SentryConfigurationException("Compatibility check failure");
+ ex.setConfigErrors(errors);
+ ex.setConfigWarnings(Lists.<String>asList(warningString.toString(), new String[0]));
+ throw ex;
+ }
+ }
+
+ private String dryRunMessage(boolean importPolicy) {
+ if (importPolicy) {
+ return "";
+ } else {
+ return "[Dry Run] ";
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ SentryConfigToolSolr solrTool = new SentryConfigToolSolr();
+ try {
+ solrTool.executeConfigTool(args);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ Throwable current = e;
+ // find the first printable message;
+ while (current != null && current.getMessage() == null) {
+ current = current.getCause();
+ }
+ String error = "";
+ if (current != null && current.getMessage() != null) {
+ error = "Message: " + current.getMessage();
+ }
+ System.out.println("The operation failed. " + error);
+ System.exit(1);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java
new file mode 100644
index 0000000..ea05db7
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellKafka.java
@@ -0,0 +1,113 @@
+/**
+ * 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.hadoop.security.UserGroupInformation;
+import org.apache.sentry.core.common.utils.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.*;
+import org.apache.sentry.provider.db.tools.SentryShellCommon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * SentryShellKafka 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 SentryShellKafka extends SentryShellCommon {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellKafka.class);
+ public static final String KAFKA_SERVICE_NAME = "sentry.service.client.kafka.service.name";
+
+ @Override
+ public void run() throws Exception {
+ Command command = null;
+ String component = AuthorizationComponent.KAFKA;
+ Configuration conf = getSentryConf();
+
+ String service = conf.get(KAFKA_SERVICE_NAME, "kafka1");
+ SentryGenericServiceClient client = SentryGenericServiceClientFactory.create(conf);
+ UserGroupInformation ugi = UserGroupInformation.getLoginUser();
+ String requestorName = ugi.getShortUserName();
+
+ if (isCreateRole) {
+ command = new CreateRoleCmd(roleName, component);
+ } else if (isDropRole) {
+ command = new DropRoleCmd(roleName, component);
+ } else if (isAddRoleGroup) {
+ command = new AddRoleToGroupCmd(roleName, groupName, component);
+ } else if (isDeleteRoleGroup) {
+ command = new DeleteRoleFromGroupCmd(roleName, groupName, component);
+ } else if (isGrantPrivilegeRole) {
+ command = new GrantPrivilegeToRoleCmd(roleName, component,
+ privilegeStr, new KafkaTSentryPrivilegeConverter(component, service));
+ } else if (isRevokePrivilegeRole) {
+ command = new RevokePrivilegeFromRoleCmd(roleName, component,
+ privilegeStr, new KafkaTSentryPrivilegeConverter(component, service));
+ } else if (isListRole) {
+ command = new ListRolesCmd(groupName, component);
+ } else if (isListPrivilege) {
+ command = new ListPrivilegesByRoleCmd(roleName, component,
+ service, new KafkaTSentryPrivilegeConverter(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 {
+ SentryShellKafka sentryShell = new SentryShellKafka();
+ try {
+ sentryShell.executeShell(args);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ Throwable current = e;
+ // find the first printable message;
+ while (current != null && current.getMessage() == null) {
+ current = current.getCause();
+ }
+ String error = "";
+ if (current != null && current.getMessage() != null) {
+ error = "Message: " + current.getMessage();
+ }
+ System.out.println("The operation failed. " + error);
+ System.exit(1);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java
new file mode 100644
index 0000000..695c008
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SentryShellSolr.java
@@ -0,0 +1,112 @@
+/**
+ * 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.hadoop.security.UserGroupInformation;
+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 component = "SOLR";
+ Configuration conf = getSentryConf();
+
+ String service = conf.get(SOLR_SERVICE_NAME, "service1");
+ SentryGenericServiceClient client = SentryGenericServiceClientFactory.create(conf);
+ UserGroupInformation ugi = UserGroupInformation.getLoginUser();
+ String requestorName = ugi.getShortUserName();
+
+ if (isCreateRole) {
+ command = new CreateRoleCmd(roleName, component);
+ } else if (isDropRole) {
+ command = new DropRoleCmd(roleName, component);
+ } else if (isAddRoleGroup) {
+ command = new AddRoleToGroupCmd(roleName, groupName, component);
+ } else if (isDeleteRoleGroup) {
+ command = new DeleteRoleFromGroupCmd(roleName, groupName, component);
+ } else if (isGrantPrivilegeRole) {
+ command = new GrantPrivilegeToRoleCmd(roleName, component,
+ privilegeStr, new SolrTSentryPrivilegeConverter(component, service));
+ } else if (isRevokePrivilegeRole) {
+ command = new RevokePrivilegeFromRoleCmd(roleName, component,
+ privilegeStr, new SolrTSentryPrivilegeConverter(component, service));
+ } else if (isListRole) {
+ command = new ListRolesCmd(groupName, component);
+ } else if (isListPrivilege) {
+ command = new ListPrivilegesByRoleCmd(roleName, component,
+ service, new SolrTSentryPrivilegeConverter(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 {
+ sentryShell.executeShell(args);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ Throwable current = e;
+ // find the first printable message;
+ while (current != null && current.getMessage() == null) {
+ current = current.getCause();
+ }
+ String error = "";
+ if (current != null && current.getMessage() != null) {
+ error = "Message: " + current.getMessage();
+ }
+ System.out.println("The operation failed. " + error);
+ System.exit(1);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConverter.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConverter.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConverter.java
new file mode 100644
index 0000000..92c6c59
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/SolrTSentryPrivilegeConverter.java
@@ -0,0 +1,137 @@
+/**
+ * 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.common.utils.SentryConstants;
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.core.model.search.SearchModelAuthorizable;
+import org.apache.sentry.core.common.validator.PrivilegeValidator;
+import org.apache.sentry.core.common.validator.PrivilegeValidatorContext;
+import org.apache.sentry.core.model.search.SearchModelAuthorizables;
+import org.apache.sentry.core.model.search.SearchPrivilegeModel;
+import org.apache.sentry.core.common.utils.KeyValue;
+import org.apache.sentry.core.common.utils.PolicyFileConstants;
+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.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class SolrTSentryPrivilegeConverter implements TSentryPrivilegeConverter {
+ private String component;
+ private String service;
+ private boolean validate;
+
+ public SolrTSentryPrivilegeConverter(String component, String service) {
+ this(component, service, true);
+ }
+
+ public SolrTSentryPrivilegeConverter(String component, String service, boolean validate) {
+ this.component = component;
+ this.service = service;
+ this.validate = validate;
+ }
+
+ public TSentryPrivilege fromString(String privilegeStr) throws Exception {
+ if (validate) {
+ validatePrivilegeHierarchy(privilegeStr);
+ }
+
+ TSentryPrivilege tSentryPrivilege = new TSentryPrivilege();
+ List<TAuthorizable> authorizables = new LinkedList<TAuthorizable>();
+ for (String authorizable : SentryConstants.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);
+ }
+ }
+
+ if (tSentryPrivilege.getAction() == null) {
+ throw new IllegalArgumentException("Privilege is invalid: action required but not specified.");
+ }
+ tSentryPrivilege.setComponent(component);
+ tSentryPrivilege.setServiceName(service);
+ tSentryPrivilege.setAuthorizables(authorizables);
+ 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(SentryConstants.KV_JOINER.join(
+ tAuthorizable.getType(), tAuthorizable.getName()));
+ }
+ }
+
+ if (!authorizables.isEmpty()) {
+ privileges.add(SentryConstants.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(SentryConstants.KV_JOINER.join(
+ PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption));
+ }
+ }
+ return SentryConstants.AUTHORIZABLE_JOINER.join(privileges);
+ }
+
+ private static void validatePrivilegeHierarchy(String privilegeStr) throws Exception {
+ List<PrivilegeValidator> validators = SearchPrivilegeModel.getInstance().getPrivilegeValidators();
+ PrivilegeValidatorContext context = new PrivilegeValidatorContext(null, privilegeStr);
+ for (PrivilegeValidator validator : validators) {
+ try {
+ validator.validate(context);
+ } catch (ConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/AddRoleToGroupCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/AddRoleToGroupCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/AddRoleToGroupCmd.java
new file mode 100644
index 0000000..a45d7e4
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/AddRoleToGroupCmd.java
@@ -0,0 +1,46 @@
+/**
+ * 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 com.google.common.collect.Sets;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
+import org.apache.sentry.provider.db.tools.SentryShellCommon;
+
+import java.util.Set;
+
+/**
+ * Command for adding groups to a role.
+ */
+public class AddRoleToGroupCmd implements Command {
+
+ private String roleName;
+ private String groups;
+ private String component;
+
+ public AddRoleToGroupCmd(String roleName, String groups, String component) {
+ this.roleName = roleName;
+ this.groups = groups;
+ this.component = component;
+ }
+
+ @Override
+ public void execute(SentryGenericServiceClient client, String requestorName) throws Exception {
+ Set<String> groupSet = Sets.newHashSet(groups.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+ client.addRoleToGroups(requestorName, roleName, component, groupSet);
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/Command.java
new file mode 100644
index 0000000..e824fb3
--- /dev/null
+++ b/sentry-service/sentry-service-client/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/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/CreateRoleCmd.java
new file mode 100644
index 0000000..da60a64
--- /dev/null
+++ b/sentry-service/sentry-service-client/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/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DeleteRoleFromGroupCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DeleteRoleFromGroupCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DeleteRoleFromGroupCmd.java
new file mode 100644
index 0000000..95f39ea
--- /dev/null
+++ b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DeleteRoleFromGroupCmd.java
@@ -0,0 +1,46 @@
+/**
+ * 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 com.google.common.collect.Sets;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
+import org.apache.sentry.provider.db.tools.SentryShellCommon;
+
+import java.util.Set;
+
+/**
+ * Command for deleting groups from a role.
+ */
+public class DeleteRoleFromGroupCmd implements Command {
+
+ private String roleName;
+ private String groups;
+ private String component;
+
+ public DeleteRoleFromGroupCmd(String roleName, String groups, String component) {
+ this.groups = groups;
+ this.roleName = roleName;
+ this.component = component;
+ }
+
+ @Override
+ public void execute(SentryGenericServiceClient client, String requestorName) throws Exception {
+ Set<String> groupSet = Sets.newHashSet(groups.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+ client.deleteRoleToGroups(requestorName, roleName, component, groupSet);
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/DropRoleCmd.java
new file mode 100644
index 0000000..ac2a328
--- /dev/null
+++ b/sentry-service/sentry-service-client/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/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/GrantPrivilegeToRoleCmd.java
new file mode 100644
index 0000000..634bb42
--- /dev/null
+++ b/sentry-service/sentry-service-client/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 TSentryPrivilegeConverter converter;
+
+ public GrantPrivilegeToRoleCmd(String roleName, String component, String privilegeStr,
+ TSentryPrivilegeConverter converter) {
+ this.roleName = roleName;
+ this.component = component;
+ this.privilegeStr = privilegeStr;
+ this.converter = converter;
+ }
+
+ @Override
+ public void execute(SentryGenericServiceClient client, String requestorName) throws Exception {
+ TSentryPrivilege privilege = converter.fromString(privilegeStr);
+ client.grantPrivilege(requestorName, roleName, component, privilege);
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListPrivilegesByRoleCmd.java
new file mode 100644
index 0000000..ce6db3a
--- /dev/null
+++ b/sentry-service/sentry-service-client/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 TSentryPrivilegeConverter converter;
+
+ public ListPrivilegesByRoleCmd(String roleName, String component, String serviceName,
+ TSentryPrivilegeConverter converter) {
+ this.roleName = roleName;
+ this.component = component;
+ this.serviceName = serviceName;
+ this.converter = converter;
+ }
+
+ @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 = converter.toString(privilege);
+ System.out.println(privilegeStr);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/01875092/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/provider/db/generic/tools/command/ListRolesCmd.java
new file mode 100644
index 0000000..6b68d06
--- /dev/null
+++ b/sentry-service/sentry-service-client/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 {
+ roles = client.listRolesByGroupName(requestorName, groupName, component);
+ }
+ if (roles != null) {
+ for (TSentryRole role : roles) {
+ System.out.println(role.getRoleName());
+ }
+ }
+ }
+}