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()); + } + } + } +}
