Java tutorial
/** * 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.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.security.auth.callback.CallbackHandler; import org.apache.hadoop.conf.Configuration; 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.SentryUserException; import org.apache.sentry.core.common.ActiveRoleSet; import org.apache.sentry.core.common.Authorizable; import org.apache.sentry.core.model.db.AccessConstants; 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 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(SentryGenericServiceClient.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) throws IOException { super(mechanism, authorizationId, protocol, serverName, props, cbh, transport); if (wrapUgi) { 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); } catch (InterruptedException e) { throw new TTransportException("Interrupted while opening underlying transport", e); } } } private void baseOpen() throws TTransportException { super.open(); } } public SentryGenericServiceClient(Configuration conf) throws IOException { this.conf = 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"); // 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); } 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); TMultiplexedProtocol protocol = new TMultiplexedProtocol(new TBinaryProtocol(transport), SentryGenericPolicyProcessor.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 roleName: Name of the role * @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.size() == 0) || (newAuthorizables == null) || (newAuthorizables.size() == 0)) { throw new SentryUserException("oldAuthorizables and newAuthorizables can't 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, AccessConstants.ALL, 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.size() > 0)) { 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.size() > 0)) { 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); } } public void close() { if (transport != null) { transport.close(); } } }