org.apache.sentry.provider.db.generic.service.thrift.SentryGenericPolicyProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sentry.provider.db.generic.service.thrift.SentryGenericPolicyProcessor.java

Source

/**
 * 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 static org.apache.sentry.provider.common.ProviderConstants.AUTHORIZABLE_JOINER;
import static org.apache.sentry.provider.common.ProviderConstants.KV_JOINER;

import java.lang.reflect.Constructor;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.hadoop.conf.Configuration;
import org.apache.sentry.SentryUserException;
import org.apache.sentry.core.common.Authorizable;
import org.apache.sentry.core.model.db.AccessConstants;
import org.apache.sentry.provider.common.AuthorizationComponent;
import org.apache.sentry.provider.db.SentryAccessDeniedException;
import org.apache.sentry.provider.db.SentryAlreadyExistsException;
import org.apache.sentry.provider.db.SentryInvalidInputException;
import org.apache.sentry.provider.db.SentryNoSuchObjectException;
import org.apache.sentry.provider.db.SentryThriftAPIMismatchException;
import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject;
import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder;
import org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer;
import org.apache.sentry.provider.db.log.entity.JsonLogEntityFactory;
import org.apache.sentry.provider.db.log.util.Constants;
import org.apache.sentry.provider.db.service.persistent.CommitContext;
import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants;
import org.apache.sentry.provider.db.service.thrift.SentryConfigurationException;
import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor;
import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
import org.apache.sentry.service.thrift.ServiceConstants.ThriftConstants;
import org.apache.sentry.service.thrift.ServiceConstants;
import org.apache.sentry.service.thrift.Status;
import org.apache.sentry.service.thrift.TSentryResponseStatus;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class SentryGenericPolicyProcessor implements SentryGenericPolicyService.Iface {
    private static final Logger LOGGER = LoggerFactory.getLogger(SentryGenericPolicyProcessor.class);
    private static final Logger AUDIT_LOGGER = LoggerFactory.getLogger(Constants.AUDIT_LOGGER_NAME_GENERIC);
    private final Configuration conf;
    private final ImmutableSet<String> adminGroups;
    private final SentryStoreLayer store;
    private final NotificationHandlerInvoker handerInvoker;

    public static final String SENTRY_GENERIC_SERVICE_NAME = "SentryGenericPolicyService";

    public SentryGenericPolicyProcessor(Configuration conf) throws Exception {
        this.store = createStore(conf);
        this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
        this.conf = conf;
        adminGroups = ImmutableSet.copyOf(
                toTrimedLower(Sets.newHashSet(conf.getStrings(ServerConfig.ADMIN_GROUPS, new String[] {}))));
    }

    @VisibleForTesting
    public SentryGenericPolicyProcessor(Configuration conf, SentryStoreLayer store) throws Exception {
        this.store = store;
        this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
        this.conf = conf;
        adminGroups = ImmutableSet.copyOf(
                toTrimedLower(Sets.newHashSet(conf.getStrings(ServerConfig.ADMIN_GROUPS, new String[] {}))));
    }

    private void authorize(String requestorUser, Set<String> requestorGroups) throws SentryAccessDeniedException {
        if (!inAdminGroups(requestorGroups)) {
            String msg = "User: " + requestorUser + " is part of " + requestorGroups
                    + " which does not, intersect admin groups " + adminGroups;
            LOGGER.warn(msg);
            throw new SentryAccessDeniedException("Access denied to " + requestorUser);
        }
    }

    private Set<String> toTrimedLower(Set<String> s) {
        if (null == s)
            return new HashSet<String>();
        Set<String> result = Sets.newHashSet();
        for (String v : s) {
            result.add(v.trim().toLowerCase());
        }
        return result;
    }

    private String toTrimedLower(String s) {
        if (Strings.isNullOrEmpty(s)) {
            return "";
        }
        return s.trim().toLowerCase();
    }

    public static Set<String> getRequestorGroups(Configuration conf, String userName) throws SentryUserException {
        return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, userName);
    }

    private boolean inAdminGroups(Set<String> requestorGroups) {
        requestorGroups = toTrimedLower(requestorGroups);
        if (Sets.intersection(adminGroups, requestorGroups).isEmpty()) {
            return false;
        } else
            return true;
    }

    public static SentryStoreLayer createStore(Configuration conf) throws SentryConfigurationException {
        SentryStoreLayer storeLayer = null;
        String Store = conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE,
                PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE_DEFAULT);

        if (Strings.isNullOrEmpty(Store)) {
            throw new SentryConfigurationException(
                    "the parameter configuration for sentry.generic.policy.store can't be empty");
        }
        try {
            storeLayer = createInstance(Store, conf, SentryStoreLayer.class);
        } catch (Exception e) {
            throw new SentryConfigurationException("Create sentryStore error: " + e.getMessage(), e);
        }
        return storeLayer;
    }

    public static List<NotificationHandler> createHandlers(Configuration conf) throws SentryConfigurationException {

        List<NotificationHandler> handlers = Lists.newArrayList();
        Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults().omitEmptyStrings()
                .split(conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_NOTIFICATION, ""));
        try {
            for (String notificationHandler : notificationHandlers) {
                handlers.add(createInstance(notificationHandler, conf, NotificationHandler.class));
            }
        } catch (Exception e) {
            throw new SentryConfigurationException("Create notificationHandlers error: " + e.getMessage(), e);
        }
        return handlers;
    }

    @SuppressWarnings("unchecked")
    public static <T> T createInstance(String className, Configuration conf, Class<T> iface) throws Exception {
        T result;
        try {
            Class clazz = Class.forName(className);
            if (!iface.isAssignableFrom(clazz)) {
                throw new IllegalArgumentException("Class " + clazz + " is not a " + iface.getName());
            }
            Constructor<T> meth = (Constructor<T>) clazz.getDeclaredConstructor(Configuration.class);
            meth.setAccessible(true);
            result = meth.newInstance(new Object[] { conf });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    private <T> Response<T> requestHandle(RequestHandler<T> handler) {
        Response<T> response = new Response<T>();
        try {
            response = handler.handle();
        } catch (SentryAccessDeniedException e) {
            LOGGER.error(e.getMessage(), e);
            response.status = Status.AccessDenied(e.getMessage(), e);
        } catch (SentryAlreadyExistsException e) {
            LOGGER.error(e.getMessage(), e);
            response.status = Status.AlreadyExists(e.getMessage(), e);
        } catch (SentryNoSuchObjectException e) {
            LOGGER.error(e.getMessage(), e);
            response.status = Status.NoSuchObject(e.getMessage(), e);
        } catch (SentryInvalidInputException e) {
            String msg = "Invalid input privilege object";
            LOGGER.error(msg, e);
            response.status = Status.InvalidInput(msg, e);
        } catch (SentryThriftAPIMismatchException e) {
            LOGGER.error(e.getMessage(), e);
            response.status = Status.THRIFT_VERSION_MISMATCH(e.getMessage(), e);
        } catch (Exception e) {
            String msg = "Unknown error:" + e.getMessage();
            LOGGER.error(msg, e);
            response.status = Status.RuntimeError(msg, e);
        }
        return response;
    }

    private PrivilegeObject toPrivilegeObject(TSentryPrivilege tSentryPrivilege) {
        Boolean grantOption;
        if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE)) {
            grantOption = true;
        } else if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.FALSE)) {
            grantOption = false;
        } else {
            grantOption = null;
        }
        return new Builder().setComponent(tSentryPrivilege.getComponent())
                .setService(tSentryPrivilege.getServiceName())
                .setAuthorizables(toAuthorizables(tSentryPrivilege.getAuthorizables()))
                .setAction(tSentryPrivilege.getAction()).withGrantOption(grantOption).build();
    }

    private TSentryPrivilege fromPrivilegeObject(PrivilegeObject privilege) {

        TSentryPrivilege tPrivilege = new TSentryPrivilege(privilege.getComponent(), privilege.getService(),
                fromAuthorizable(privilege.getAuthorizables()), privilege.getAction());
        if (privilege.getGrantOption() == null) {
            tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
        } else if (privilege.getGrantOption()) {
            tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
        } else {
            tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
        }
        return tPrivilege;
    }

    private List<TAuthorizable> fromAuthorizable(List<? extends Authorizable> authorizables) {
        List<TAuthorizable> tAuthorizables = Lists.newArrayList();
        for (Authorizable authorizable : authorizables) {
            tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
        }
        return tAuthorizables;
    }

    private List<? extends Authorizable> toAuthorizables(List<TAuthorizable> tAuthorizables) {
        List<Authorizable> authorizables = Lists.newArrayList();
        if (tAuthorizables == null) {
            return authorizables;
        }
        for (final TAuthorizable tAuthorizable : tAuthorizables) {
            authorizables.add(new Authorizable() {
                @Override
                public String getTypeName() {
                    return tAuthorizable.getType();
                }

                @Override
                public String getName() {
                    return tAuthorizable.getName();
                }
            });
        }
        return authorizables;
    }

    private Set<String> buildPermissions(Set<PrivilegeObject> privileges) {
        Set<String> permissions = Sets.newHashSet();
        for (PrivilegeObject privilege : privileges) {
            List<String> hierarchy = Lists.newArrayList();
            if (hasComponentServerPrivilege(privilege.getComponent())) {
                hierarchy.add(KV_JOINER.join("server", privilege.getService()));
            }
            for (Authorizable authorizable : privilege.getAuthorizables()) {
                hierarchy.add(KV_JOINER.join(authorizable.getTypeName(), authorizable.getName()));
            }
            hierarchy.add(KV_JOINER.join("action", privilege.getAction()));
            permissions.add(AUTHORIZABLE_JOINER.join(hierarchy));
        }
        return permissions;
    }

    private boolean hasComponentServerPrivilege(String component) {
        //judge the component whether has the server privilege, for example: sqoop has the privilege on the server
        return AuthorizationComponent.SQOOP.equalsIgnoreCase(component);
    }

    @Override
    public TCreateSentryRoleResponse create_sentry_role(final TCreateSentryRoleRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.createRole(request.getComponent(), request.getRoleName(),
                        request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TCreateSentryRoleResponse tResponse = new TCreateSentryRoleResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.create_sentry_role(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for create role: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TDropSentryRoleResponse drop_sentry_role(final TDropSentryRoleRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.dropRole(request.getComponent(), request.getRoleName(),
                        request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TDropSentryRoleResponse tResponse = new TDropSentryRoleResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.drop_sentry_role(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for drop role: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege(
            final TAlterSentryRoleGrantPrivilegeRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                CommitContext context = store.alterRoleGrantPrivilege(request.getComponent(), request.getRoleName(),
                        toPrivilegeObject(request.getPrivilege()), request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TAlterSentryRoleGrantPrivilegeResponse tResponse = new TAlterSentryRoleGrantPrivilegeResponse(
                respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.alter_sentry_role_grant_privilege(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for grant privilege to role: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege(
            final TAlterSentryRoleRevokePrivilegeRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                CommitContext context = store.alterRoleRevokePrivilege(request.getComponent(),
                        request.getRoleName(), toPrivilegeObject(request.getPrivilege()),
                        request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TAlterSentryRoleRevokePrivilegeResponse tResponse = new TAlterSentryRoleRevokePrivilegeResponse(
                respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.alter_sentry_role_revoke_privilege(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for revoke privilege from role: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(
            final TAlterSentryRoleAddGroupsRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.alterRoleAddGroups(request.getComponent(), request.getRoleName(),
                        request.getGroups(), request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TAlterSentryRoleAddGroupsResponse tResponse = new TAlterSentryRoleAddGroupsResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.alter_sentry_role_add_groups(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for add role to group: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(
            final TAlterSentryRoleDeleteGroupsRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.alterRoleDeleteGroups(request.getComponent(), request.getRoleName(),
                        request.getGroups(), request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TAlterSentryRoleDeleteGroupsResponse tResponse = new TAlterSentryRoleDeleteGroupsResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.alter_sentry_role_delete_groups(respose.context, request, tResponse);
        }

        try {
            AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(request, tResponse, conf)
                    .toJsonFormatLog());
        } catch (Exception e) {
            // if any exception, log the exception.
            String msg = "Error creating audit log for delete role from group: " + e.getMessage();
            LOGGER.error(msg, e);
        }
        return tResponse;
    }

    @Override
    public TListSentryRolesResponse list_sentry_roles_by_group(final TListSentryRolesRequest request)
            throws TException {
        Response<Set<TSentryRole>> respose = requestHandle(new RequestHandler<Set<TSentryRole>>() {
            @Override
            public Response<Set<TSentryRole>> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
                if (AccessConstants.ALL.equalsIgnoreCase(request.getGroupName())) {
                    //check all groups which requestorUserName belongs to
                } else {
                    boolean admin = inAdminGroups(groups);
                    //Only admin users can list all roles in the system ( groupname = null)
                    //Non admin users are only allowed to list only groups which they belong to
                    if (!admin && (request.getGroupName() == null || !groups.contains(request.getGroupName()))) {
                        throw new SentryAccessDeniedException("Access denied to " + request.getRequestorUserName());
                    }
                    groups.clear();
                    groups.add(request.getGroupName());
                }

                Set<String> roleNames = store.getRolesByGroups(request.getComponent(), groups);
                Set<TSentryRole> tSentryRoles = Sets.newHashSet();
                for (String roleName : roleNames) {
                    Set<String> groupsForRoleName = store.getGroupsByRoles(request.getComponent(),
                            Sets.newHashSet(roleName));
                    tSentryRoles.add(new TSentryRole(roleName, groupsForRoleName));
                }
                return new Response<Set<TSentryRole>>(Status.OK(), tSentryRoles);
            }
        });
        TListSentryRolesResponse tResponse = new TListSentryRolesResponse();
        tResponse.setStatus(respose.status);
        tResponse.setRoles(respose.content);
        return tResponse;
    }

    @Override
    public TListSentryPrivilegesResponse list_sentry_privileges_by_role(final TListSentryPrivilegesRequest request)
            throws TException {
        Response<Set<TSentryPrivilege>> respose = requestHandle(new RequestHandler<Set<TSentryPrivilege>>() {
            @Override
            public Response<Set<TSentryPrivilege>> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
                if (!inAdminGroups(groups)) {
                    Set<String> roleNamesForGroups = toTrimedLower(
                            store.getRolesByGroups(request.getComponent(), groups));
                    if (!roleNamesForGroups.contains(toTrimedLower(request.getRoleName()))) {
                        throw new SentryAccessDeniedException("Access denied to " + request.getRequestorUserName());
                    }
                }
                Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
                        request.getServiceName(), Sets.newHashSet(request.getRoleName()), null,
                        toAuthorizables(request.getAuthorizables()));
                Set<TSentryPrivilege> tSentryPrivileges = Sets.newHashSet();
                for (PrivilegeObject privilege : privileges) {
                    tSentryPrivileges.add(fromPrivilegeObject(privilege));
                }
                return new Response<Set<TSentryPrivilege>>(Status.OK(), tSentryPrivileges);
            }
        });
        TListSentryPrivilegesResponse tResponse = new TListSentryPrivilegesResponse();
        tResponse.setStatus(respose.status);
        tResponse.setPrivileges(respose.content);
        return tResponse;
    }

    @Override
    public TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider(
            final TListSentryPrivilegesForProviderRequest request) throws TException {
        Response<Set<String>> respose = requestHandle(new RequestHandler<Set<String>>() {
            @Override
            public Response<Set<String>> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                Set<String> activeRoleNames = toTrimedLower(request.getRoleSet().getRoles());
                Set<String> roleNamesForGroups = store.getRolesByGroups(request.getComponent(),
                        request.getGroups());
                Set<String> rolesToQuery = request.getRoleSet().isAll() ? roleNamesForGroups
                        : Sets.intersection(activeRoleNames, roleNamesForGroups);
                Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
                        request.getServiceName(), rolesToQuery, null, toAuthorizables(request.getAuthorizables()));
                return new Response<Set<String>>(Status.OK(), buildPermissions(privileges));
            }
        });
        TListSentryPrivilegesForProviderResponse tResponse = new TListSentryPrivilegesForProviderResponse();
        tResponse.setStatus(respose.status);
        tResponse.setPrivileges(respose.content);
        return tResponse;
    }

    @Override
    public TDropPrivilegesResponse drop_sentry_privilege(final TDropPrivilegesRequest request) throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.dropPrivilege(request.getComponent(),
                        toPrivilegeObject(request.getPrivilege()), request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TDropPrivilegesResponse tResponse = new TDropPrivilegesResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.drop_sentry_privilege(respose.context, request, tResponse);
        }
        return tResponse;
    }

    @Override
    public TRenamePrivilegesResponse rename_sentry_privilege(final TRenamePrivilegesRequest request)
            throws TException {
        Response<Void> respose = requestHandle(new RequestHandler<Void>() {
            @Override
            public Response<Void> handle() throws Exception {
                validateClientVersion(request.getProtocol_version());
                authorize(request.getRequestorUserName(), getRequestorGroups(conf, request.getRequestorUserName()));
                CommitContext context = store.renamePrivilege(request.getComponent(), request.getServiceName(),
                        toAuthorizables(request.getOldAuthorizables()),
                        toAuthorizables(request.getNewAuthorizables()), request.getRequestorUserName());
                return new Response<Void>(Status.OK(), context);
            }
        });

        TRenamePrivilegesResponse tResponse = new TRenamePrivilegesResponse(respose.status);
        if (Status.OK.getCode() == respose.status.getValue()) {
            handerInvoker.rename_sentry_privilege(respose.context, request, tResponse);
        }
        return tResponse;
    }

    private static class Response<T> {
        TSentryResponseStatus status;
        CommitContext context;
        T content;

        Response() {
        }

        Response(TSentryResponseStatus status, CommitContext context) {
            this(status, context, null);
        }

        Response(TSentryResponseStatus status, T content) {
            this(status, null, content);
        }

        Response(TSentryResponseStatus status, CommitContext context, T content) {
            this.status = status;
            this.context = context;
            this.content = content;
        }
    }

    private interface RequestHandler<T> {
        public Response<T> handle() throws Exception;
    }

    private static void validateClientVersion(int protocol_version) throws SentryThriftAPIMismatchException {
        if (ServiceConstants.ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT != protocol_version) {
            String msg = "Sentry thrift API protocol version mismatch: Client thrift version " + "is: "
                    + protocol_version + " , server thrift verion " + "is "
                    + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT;
            throw new SentryThriftAPIMismatchException(msg);
        }
    }
}