blob: 8ede0698f1a6a327fa97b37b5fa4c79d207ef0de [file] [log] [blame]
/**
* 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.service.thrift;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.Partition;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.sentry.SentryUserException;
import org.apache.sentry.core.model.db.AccessConstants;
import org.apache.sentry.hdfs.ExtendedMetastoreClient;
import org.apache.sentry.hdfs.HMSPaths;
import org.apache.sentry.hdfs.MetastoreClient;
import org.apache.sentry.hdfs.PathsUpdate;
import org.apache.sentry.hdfs.PermissionsUpdate;
import org.apache.sentry.hdfs.UpdateableAuthzPaths;
import org.apache.sentry.provider.common.GroupMappingService;
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.log.entity.JsonLogEntityFactory;
import org.apache.sentry.provider.db.log.util.Constants;
import org.apache.sentry.provider.db.service.UpdateForwarder;
import org.apache.sentry.provider.db.service.UpdateForwarder.ExternalImageRetriever;
import org.apache.sentry.provider.db.service.UpdateablePermissions;
import org.apache.sentry.provider.db.service.persistent.CommitContext;
import org.apache.sentry.provider.db.service.persistent.SentryStore;
import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants.PolicyStoreServerConfig;
import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
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.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@SuppressWarnings("unused")
public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
private static final Logger LOGGER = LoggerFactory.getLogger(SentryPolicyStoreProcessor.class);
private static final Logger AUDIT_LOGGER = LoggerFactory.getLogger(Constants.AUDIT_LOGGER_NAME);
public static final String SENTRY_POLICY_SERVICE_NAME = "SentryPolicyService";
private final String name;
private final Configuration conf;
private final SentryStore sentryStore;
private final NotificationHandlerInvoker notificationHandlerInvoker;
private final ImmutableSet<String> adminGroups;
private boolean isReady;
private final UpdateForwarder<PathsUpdate> pathsUpdater;
private final UpdateForwarder<PermissionsUpdate> permsUpdater;
// Initialized to some value > 1 so that the first update notification
// will trigger a full Image fetch
private final AtomicLong permSeqNum = new AtomicLong(5);
public SentryPolicyStoreProcessor(String name, Configuration conf) throws Exception {
super();
this.name = name;
this.conf = conf;
this.notificationHandlerInvoker = new NotificationHandlerInvoker(conf,
createHandlers(conf));
isReady = false;
sentryStore = new SentryStore(conf);
isReady = true;
adminGroups = ImmutableSet.copyOf(toTrimedLower(Sets.newHashSet(conf.getStrings(
ServerConfig.ADMIN_GROUPS, new String[]{}))));
HiveConf hiveConf = new HiveConf(conf, Configuration.class);
if (conf.getBoolean(ServerConfig.SENTRY_HDFS_INTEGRATION_ENABLE, true)) {
final MetastoreClient hmsClient = new ExtendedMetastoreClient(hiveConf);
final String[] pathPrefixes = conf
.getStrings(ServerConfig.SENTRY_HDFS_INTEGRATION_PATH_PREFIXES, new String[]{"/"});
pathsUpdater = new UpdateForwarder<PathsUpdate>(new UpdateableAuthzPaths(
pathPrefixes), createHMSImageRetriever(pathPrefixes, hmsClient), 100);
permsUpdater = new UpdateForwarder<PermissionsUpdate>(
new UpdateablePermissions(sentryStore), sentryStore, 100);
} else {
pathsUpdater = null;
permsUpdater = null;
}
}
private ExternalImageRetriever<PathsUpdate> createHMSImageRetriever(
final String[] pathPrefixes, final MetastoreClient hmsClient) {
return new ExternalImageRetriever<PathsUpdate>() {
@Override
public PathsUpdate retrieveFullImage(long currSeqNum) {
PathsUpdate tempUpdate = new PathsUpdate(currSeqNum, false);
List<Database> allDatabases = hmsClient.getAllDatabases();
for (Database db : allDatabases) {
tempUpdate.newPathChange(db.getName()).addToAddPaths(
PathsUpdate.cleanPath(db.getLocationUri()));
List<Table> allTables = hmsClient.getAllTablesOfDatabase(db);
for (Table tbl : allTables) {
TPathChanges tblPathChange = tempUpdate.newPathChange(tbl
.getDbName() + "." + tbl.getTableName());
List<Partition> tblParts = hmsClient.listAllPartitions(db, tbl);
tblPathChange.addToAddPaths(PathsUpdate.cleanPath(tbl.getSd()
.getLocation() == null ? db.getLocationUri() : tbl
.getSd().getLocation()));
for (Partition part : tblParts) {
tblPathChange.addToAddPaths(PathsUpdate.cleanPath(part.getSd()
.getLocation()));
}
}
}
UpdateableAuthzPaths tmpAuthzPaths = new UpdateableAuthzPaths(
pathPrefixes);
tmpAuthzPaths.updatePartial(Lists.newArrayList(tempUpdate),
new ReentrantReadWriteLock());
PathsUpdate retUpdate = new PathsUpdate(currSeqNum, true);
retUpdate.getThriftObject().setPathsDump(
tmpAuthzPaths.getPathsDump().createPathsDump());
return retUpdate;
}
};
}
public void stop() {
if (isReady) {
sentryStore.stop();
}
}
@VisibleForTesting
static List<NotificationHandler> createHandlers(Configuration conf)
throws SentryConfigurationException {
List<NotificationHandler> handlers = Lists.newArrayList();
Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults()
.omitEmptyStrings().split(conf.get(PolicyStoreServerConfig.NOTIFICATION_HANDLERS, ""));
for (String notificationHandler : notificationHandlers) {
Class<?> clazz = null;
try {
clazz = Class.forName(notificationHandler);
if (!NotificationHandler.class.isAssignableFrom(clazz)) {
throw new SentryConfigurationException("Class " + notificationHandler + " is not a " +
NotificationHandler.class.getName());
}
} catch (ClassNotFoundException e) {
throw new SentryConfigurationException("Value " + notificationHandler +
" is not a class", e);
}
Preconditions.checkNotNull(clazz, "Error class cannot be null");
try {
Constructor<?> constructor = clazz.getConstructor(Configuration.class);
handlers.add((NotificationHandler)constructor.newInstance(conf));
} catch (Exception e) {
throw new SentryConfigurationException("Error attempting to create " + notificationHandler, e);
}
}
return handlers;
}
@VisibleForTesting
public Configuration getSentryStoreConf() {
return conf;
}
private static Set<String> toTrimedLower(Set<String> s) {
Set<String> result = Sets.newHashSet();
for (String v : s) {
result.add(v.trim().toLowerCase());
}
return result;
}
private boolean inAdminGroups(Set<String> requestorGroups) {
requestorGroups = toTrimedLower(requestorGroups);
if (Sets.intersection(adminGroups, requestorGroups).isEmpty()) {
return false;
} else return true;
}
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);
}
}
@Override
public TCreateSentryRoleResponse create_sentry_role(
TCreateSentryRoleRequest request) throws TException {
TCreateSentryRoleResponse response = new TCreateSentryRoleResponse();
try {
authorize(request.getRequestorUserName(),
getRequestorGroups(request.getRequestorUserName()));
CommitContext commitContext = sentryStore.createSentryRole(request.getRoleName(),
request.getRequestorUserName());
response.setStatus(Status.OK());
notificationHandlerInvoker.create_sentry_role(commitContext,
request, response);
} catch (SentryAlreadyExistsException e) {
String msg = "Role: " + request + " already exists.";
LOGGER.error(msg, e);
response.setStatus(Status.AlreadyExists(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege
(TAlterSentryRoleGrantPrivilegeRequest request) throws TException {
TAlterSentryRoleGrantPrivilegeResponse response = new TAlterSentryRoleGrantPrivilegeResponse();
try {
CommitContext commitContext = sentryStore.alterSentryRoleGrantPrivilege(request.getRoleName(),
request.getPrivilege());
response.setStatus(Status.OK());
notificationHandlerInvoker.alter_sentry_role_grant_privilege(commitContext,
request, response);
String authzObj = getAuthzObj(request.getPrivilege());
if (authzObj != null) {
PermissionsUpdate update = new PermissionsUpdate(permSeqNum.incrementAndGet(), false);
update.addPrivilegeUpdate(authzObj).putToAddPrivileges(
request.getRoleName(),
SentryStore.ACTION_MAPPING.get(request.getPrivilege().getAction().toUpperCase())
.SYMBOL);
permsUpdater.handleUpdateNotification(update);
LOGGER.info("Authz Perm preUpdate [" + update.getSeqNum() + "]..");
}
} catch (SentryNoSuchObjectException e) {
String msg = "Role: " + request.getRoleName() + " doesn't exist.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryInvalidInputException e) {
String msg = "Invalid input privilege object";
LOGGER.error(msg, e);
response.setStatus(Status.InvalidInput(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege
(TAlterSentryRoleRevokePrivilegeRequest request) throws TException {
TAlterSentryRoleRevokePrivilegeResponse response = new TAlterSentryRoleRevokePrivilegeResponse();
try {
CommitContext commitContext = sentryStore.alterSentryRoleRevokePrivilege(request.getRoleName(),
request.getPrivilege());
response.setStatus(Status.OK());
notificationHandlerInvoker.alter_sentry_role_revoke_privilege(commitContext,
request, response);
String authzObj = getAuthzObj(request.getPrivilege());
if (authzObj != null) {
PermissionsUpdate update = new PermissionsUpdate(permSeqNum.incrementAndGet(), false);
update.addPrivilegeUpdate(authzObj).putToDelPrivileges(
request.getRoleName(),
SentryStore.ACTION_MAPPING.get(request.getPrivilege().getAction().toUpperCase())
.SYMBOL);
permsUpdater.handleUpdateNotification(update);
LOGGER.info("Authz Perm preUpdate [" + update.getSeqNum() + ", " + authzObj + "]..");
}
} catch (SentryNoSuchObjectException e) {
String msg = "Privilege: [server=" + request.getPrivilege().getServerName() +
",db=" + request.getPrivilege().getDbName() +
",table=" + request.getPrivilege().getTableName() +
",URI=" + request.getPrivilege().getURI() +
",action=" + request.getPrivilege().getAction() + "] doesn't exist.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryInvalidInputException e) {
String msg = "Invalid input privilege object";
LOGGER.error(msg, e);
response.setStatus(Status.InvalidInput(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TDropSentryRoleResponse drop_sentry_role(
TDropSentryRoleRequest request) throws TException {
TDropSentryRoleResponse response = new TDropSentryRoleResponse();
TSentryResponseStatus status;
try {
authorize(request.getRequestorUserName(),
getRequestorGroups(request.getRequestorUserName()));
CommitContext commitContext = sentryStore.dropSentryRole(request.getRoleName());
response.setStatus(Status.OK());
notificationHandlerInvoker.drop_sentry_role(commitContext,
request, response);
PermissionsUpdate update = new PermissionsUpdate(permSeqNum.incrementAndGet(), false);
update.addPrivilegeUpdate(PermissionsUpdate.ALL_AUTHZ_OBJ).putToDelPrivileges(
request.getRoleName(), PermissionsUpdate.ALL_AUTHZ_OBJ);
update.addRoleUpdate(request.getRoleName()).addToDelGroups(PermissionsUpdate.ALL_GROUPS);
permsUpdater.handleUpdateNotification(update);
LOGGER.info("Authz Perm preUpdate [" + update.getSeqNum() + ", " + request.getRoleName() + "]..");
} catch (SentryNoSuchObjectException e) {
String msg = "Role :" + request + " does not exist.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(
TAlterSentryRoleAddGroupsRequest request) throws TException {
TAlterSentryRoleAddGroupsResponse response = new TAlterSentryRoleAddGroupsResponse();
try {
authorize(request.getRequestorUserName(),
getRequestorGroups(request.getRequestorUserName()));
CommitContext commitContext = sentryStore.alterSentryRoleAddGroups(request.getRequestorUserName(),
request.getRoleName(), request.getGroups());
response.setStatus(Status.OK());
notificationHandlerInvoker.alter_sentry_role_add_groups(commitContext,
request, response);
PermissionsUpdate update = new PermissionsUpdate(permSeqNum.incrementAndGet(), false);
TRoleChanges rUpdate = update.addRoleUpdate(request.getRoleName());
for (TSentryGroup group : request.getGroups()) {
rUpdate.addToAddGroups(group.getGroupName());
}
permsUpdater.handleUpdateNotification(update);
LOGGER.info("Authz Perm preUpdate [" + update.getSeqNum() + ", " + request.getRoleName() + "]..");
} catch (SentryNoSuchObjectException e) {
String msg = "Role: " + request + " does not exist.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(
TAlterSentryRoleDeleteGroupsRequest request) throws TException {
TAlterSentryRoleDeleteGroupsResponse response = new TAlterSentryRoleDeleteGroupsResponse();
try {
authorize(request.getRequestorUserName(),
getRequestorGroups(request.getRequestorUserName()));
CommitContext commitContext = sentryStore.alterSentryRoleDeleteGroups(request.getRoleName(),
request.getGroups());
response.setStatus(Status.OK());
notificationHandlerInvoker.alter_sentry_role_delete_groups(commitContext,
request, response);
PermissionsUpdate update = new PermissionsUpdate(permSeqNum.incrementAndGet(), false);
TRoleChanges rUpdate = update.addRoleUpdate(request.getRoleName());
for (TSentryGroup group : request.getGroups()) {
rUpdate.addToDelGroups(group.getGroupName());
}
permsUpdater.handleUpdateNotification(update);
LOGGER.info("Authz Perm preUpdate [" + update.getSeqNum() + ", " + request.getRoleName() + "]..");
} catch (SentryNoSuchObjectException e) {
String msg = "Role: " + request + " does not exist.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error adding groups to role: " + request;
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance().createJsonLogEntity(
request, response, conf).toJsonFormatLog());
return response;
}
@Override
public TListSentryRolesResponse list_sentry_roles_by_group(
TListSentryRolesRequest request) throws TException {
TListSentryRolesResponse response = new TListSentryRolesResponse();
TSentryResponseStatus status;
Set<TSentryRole> roleSet = new HashSet<TSentryRole>();
Set<String> groups = new HashSet<String>();
boolean checkAllGroups = false;
try {
// Don't check admin permissions for listing requestor's own roles
if (AccessConstants.ALL.equalsIgnoreCase(request.getGroupName())) {
groups = getRequestorGroups(request.getRequestorUserName());
checkAllGroups = true;
} else {
authorize(request.getRequestorUserName(),
getRequestorGroups(request.getRequestorUserName()));
groups.add(request.getGroupName());
}
roleSet = sentryStore.getTSentryRolesByGroupName(groups, checkAllGroups);
response.setRoles(roleSet);
response.setStatus(Status.OK());
} catch (SentryNoSuchObjectException e) {
response.setRoles(roleSet);
String msg = "Role: " + request + " couldn't be retrieved.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
return response;
}
@Override
public TListSentryPrivilegesResponse list_sentry_privileges_by_role(
TListSentryPrivilegesRequest request) throws TException {
TListSentryPrivilegesResponse response = new TListSentryPrivilegesResponse();
TSentryResponseStatus status;
Set<TSentryPrivilege> privilegeSet = new HashSet<TSentryPrivilege>();
String subject = request.getRequestorUserName();
try {
Set<String> groups = getRequestorGroups(subject);
Boolean admin = inAdminGroups(groups);
if(!admin) {
Set<String> roleNamesForGroups = toTrimedLower(sentryStore.getRoleNamesForGroups(groups));
if(!roleNamesForGroups.contains(request.getRoleName().trim().toLowerCase())) {
throw new SentryAccessDeniedException("Access denied to " + subject);
}
}
if (request.isSetAuthorizableHierarchy()) {
TSentryAuthorizable authorizableHierarchy = request.getAuthorizableHierarchy();
privilegeSet = sentryStore.getTSentryPrivileges(Sets.newHashSet(request.getRoleName()), authorizableHierarchy);
} else {
privilegeSet = sentryStore.getAllTSentryPrivilegesByRoleName(request.getRoleName());
}
response.setPrivileges(privilegeSet);
response.setStatus(Status.OK());
} catch (SentryNoSuchObjectException e) {
response.setPrivileges(privilegeSet);
String msg = "Privilege: " + request + " couldn't be retrieved.";
LOGGER.error(msg, e);
response.setStatus(Status.NoSuchObject(msg, e));
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
return response;
}
/**
* This method was created specifically for ProviderBackend.getPrivileges() and is not meant
* to be used for general privilege retrieval. More details in the .thrift file.
*/
@Override
public TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider(
TListSentryPrivilegesForProviderRequest request) throws TException {
TListSentryPrivilegesForProviderResponse response = new TListSentryPrivilegesForProviderResponse();
response.setPrivileges(new HashSet<String>());
try {
Set<String> privilegesForProvider = sentryStore.listSentryPrivilegesForProvider(
request.getGroups(), request.getRoleSet(), request.getAuthorizableHierarchy());
response.setPrivileges(privilegesForProvider);
if (((privilegesForProvider == null)||(privilegesForProvider.size() == 0))&&(request.getAuthorizableHierarchy() != null)) {
if (sentryStore.hasAnyServerPrivileges(
request.getGroups(), request.getRoleSet(), request.getAuthorizableHierarchy().getServer())) {
// REQUIRED for ensuring 'default' Db is accessible by any user
// with privileges to atleast 1 object with the specific server as root
// Need some way to specify that even though user has no privilege
// For the specific AuthorizableHierarchy.. he has privilege on
// atleast 1 object in the server hierarchy
HashSet<String> serverPriv = Sets.newHashSet("server=+");
response.setPrivileges(serverPriv);
}
}
response.setStatus(Status.OK());
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: " + e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
return response;
}
// retrieve the group mapping for the given user name
private Set<String> getRequestorGroups(String userName)
throws SentryUserException {
return getGroupsFromUserName(this.conf, userName);
}
public static Set<String> getGroupsFromUserName(Configuration conf,
String userName) throws SentryUserException {
String groupMapping = conf.get(ServerConfig.SENTRY_STORE_GROUP_MAPPING,
ServerConfig.SENTRY_STORE_GROUP_MAPPING_DEFAULT);
String authResoruce = conf
.get(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE);
// load the group mapping provider class
GroupMappingService groupMappingService;
try {
Constructor<?> constrctor = Class.forName(groupMapping)
.getDeclaredConstructor(Configuration.class, String.class);
constrctor.setAccessible(true);
groupMappingService = (GroupMappingService) constrctor
.newInstance(new Object[] { conf, authResoruce });
} catch (NoSuchMethodException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (SecurityException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (ClassNotFoundException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (InstantiationException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (IllegalAccessException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (IllegalArgumentException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
} catch (InvocationTargetException e) {
throw new SentryUserException("Unable to instantiate group mapping", e);
}
return groupMappingService.getGroups(userName);
}
@Override
public TDropPrivilegesResponse drop_sentry_privilege(
TDropPrivilegesRequest request) throws TException {
TDropPrivilegesResponse response = new TDropPrivilegesResponse();
try {
authorize(request.getRequestorUserName(), adminGroups);
sentryStore.dropPrivilege(request.getAuthorizable());
response.setStatus(Status.OK());
// TODO : Sentry - HDFS : Have to handle this
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: "
+ e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
return response;
}
@Override
public TRenamePrivilegesResponse rename_sentry_privilege(
TRenamePrivilegesRequest request) throws TException {
TRenamePrivilegesResponse response = new TRenamePrivilegesResponse();
try {
authorize(request.getRequestorUserName(), adminGroups);
sentryStore.renamePrivilege(request.getOldAuthorizable(),
request.getNewAuthorizable(), request.getRequestorUserName());
response.setStatus(Status.OK());
// TODO : Sentry - HDFS : Have to handle this
} catch (SentryAccessDeniedException e) {
LOGGER.error(e.getMessage(), e);
response.setStatus(Status.AccessDenied(e.getMessage(), e));
} catch (Exception e) {
String msg = "Unknown error for request: " + request + ", message: "
+ e.getMessage();
LOGGER.error(msg, e);
response.setStatus(Status.RuntimeError(msg, e));
}
return response;
}
@Override
public void handle_hms_notification(TPathsUpdate update) throws TException {
if (pathsUpdater == null) {
throw new TException("HiveMetastore Path Cache not enabled !!");
}
try {
PathsUpdate hmsUpdate = new PathsUpdate(update);
pathsUpdater.handleUpdateNotification(hmsUpdate);
LOGGER.info("Authz Path preUpdate [" + hmsUpdate.getSeqNum() + "]..");
} catch (Exception e) {
LOGGER.error("Error handling notification from HMS", e);
throw new TException(e);
}
}
@Override
public TAuthzUpdateResponse get_all_authz_updates_from(long permSeqNum, long pathSeqNum) throws TException {
if (pathsUpdater == null) {
throw new TException("HiveMetastore Path Cache not enabled !!");
}
List<PathsUpdate> pathUpdates = pathsUpdater.getAllUpdatesFrom(pathSeqNum);
List<PermissionsUpdate> permUpdates = permsUpdater.getAllUpdatesFrom(permSeqNum);
TAuthzUpdateResponse retVal = new TAuthzUpdateResponse();
retVal.setAuthzPathUpdate(new LinkedList<TPathsUpdate>());
retVal.setAuthzPermUpdate(new LinkedList<TPermissionsUpdate>());
try {
for (PathsUpdate update : pathUpdates) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("### Sending PATH preUpdate seq [" + update.getSeqNum() + "] ###");
LOGGER.debug("### Sending PATH preUpdate [" + update.getThriftObject() + "] ###");
}
retVal.getAuthzPathUpdate().add(update.getThriftObject());
}
for (PermissionsUpdate update : permUpdates) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("### Sending PERM preUpdate seq [" + update.getSeqNum() + "] ###");
LOGGER.debug("### Sending PERM preUpdate [" + update.getThriftObject() + "] ###");
}
retVal.getAuthzPermUpdate().add(update.getThriftObject());
}
} catch (Exception e) {
LOGGER.error("Error Sending updates to downstream Cache", e);
throw new TException(e);
}
return retVal;
}
@Override
public Map<String, List<String>> get_all_related_paths(String path,
boolean exactMatch) throws TException {
if (pathsUpdater == null) {
throw new TException("HiveMetastore Path Cache not enabled !!");
}
// Map<String, LinkedList<String>> relatedPaths = hmsPathCache
// .getAllRelatedPaths(path, exactMatch);
return new HashMap<String, List<String>>();
}
private String getAuthzObj(TSentryPrivilege privilege) {
String authzObj = null;
if (!SentryStore.isNULL(privilege.getDbName())) {
String dbName = privilege.getDbName();
String tblName = privilege.getTableName();
if (tblName == null) {
authzObj = dbName;
} else {
authzObj = dbName + "." + tblName;
}
}
return authzObj;
}
}