You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by ka...@apache.org on 2018/06/21 20:59:17 UTC
sentry git commit: SENTRY-2274: Grant and revoke owner privileges
based on HMS updates(server-side) (Kalyan Kumar Kalvagadda reviewed by Sergio
Pena)
Repository: sentry
Updated Branches:
refs/heads/master f330be532 -> 4d9bc9cea
SENTRY-2274: Grant and revoke owner privileges based on HMS updates(server-side) (Kalyan Kumar Kalvagadda reviewed by Sergio Pena)
Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/4d9bc9ce
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/4d9bc9ce
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/4d9bc9ce
Branch: refs/heads/master
Commit: 4d9bc9cea94f13b7994817d33c016c776fa7dcda
Parents: f330be5
Author: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Authored: Thu Jun 21 15:59:05 2018 -0500
Committer: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Committed: Thu Jun 21 15:59:05 2018 -0500
----------------------------------------------------------------------
.../java/org/apache/sentry/SentryOwnerInfo.java | 84 +++++++
.../org/apache/sentry/hdfs/SentryPlugin.java | 40 ++--
.../api/service/thrift/SentryMetrics.java | 2 +
.../thrift/SentryPolicyStoreProcessor.java | 227 ++++++++++++++++++-
.../provider/db/SentryPolicyStorePlugin.java | 22 +-
.../db/service/persistent/CounterWait.java | 4 +-
.../db/service/persistent/SentryStore.java | 208 ++++++++++++++++-
.../thrift/TestSentryPolicyStoreProcessor.java | 125 +++++++++-
.../db/service/persistent/TestSentryStore.java | 204 +++++++++++++++++
9 files changed, 869 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/SentryOwnerInfo.java
----------------------------------------------------------------------
diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/SentryOwnerInfo.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/SentryOwnerInfo.java
new file mode 100644
index 0000000..ee4fce5
--- /dev/null
+++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/SentryOwnerInfo.java
@@ -0,0 +1,84 @@
+/**
+ * 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;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.service.common.ServiceConstants.SentryEntityType;
+
+/**
+ * This class holds the owner name and the Type
+ */
+public class SentryOwnerInfo {
+ private String ownerName;
+ private SentryEntityType ownerType;
+
+ public SentryOwnerInfo (SentryEntityType type, String name) {
+ ownerType = type;
+ ownerName = name;
+ }
+
+ public void setOwnerName(String name) {
+ ownerName = name;
+ }
+
+ public String getOwnerName() {
+ return ownerName;
+ }
+
+ public SentryEntityType getOwnerType() {
+ return ownerType;
+ }
+
+ public void setOwnerType(SentryEntityType type) {
+ ownerType = type;
+ }
+
+ @Override
+ public String toString() {
+ return "Owner Type: " + ownerType.toString() + ", Owner Name: " + ownerName;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((ownerName == null) ? 0 : ownerName.hashCode());
+ result = prime * result + ownerType.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ SentryOwnerInfo other = (SentryOwnerInfo) obj;
+
+ if(ownerType != other.getOwnerType()) {
+ return false;
+ }
+ return StringUtils.equals(ownerName, other.ownerName);
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
index b5e01e4..6ff3c82 100644
--- a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
+++ b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
@@ -38,8 +38,6 @@ import org.apache.sentry.provider.db.service.persistent.SentryStore;
import org.apache.sentry.api.common.SentryServiceUtil;
import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddGroupsRequest;
import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteGroupsRequest;
-import org.apache.sentry.api.service.thrift.TAlterSentryRoleGrantPrivilegeRequest;
-import org.apache.sentry.api.service.thrift.TAlterSentryRoleRevokePrivilegeRequest;
import org.apache.sentry.api.service.thrift.TDropPrivilegesRequest;
import org.apache.sentry.api.service.thrift.TDropSentryRoleRequest;
import org.apache.sentry.api.service.thrift.TRenamePrivilegesRequest;
@@ -251,17 +249,18 @@ public class SentryPlugin implements SentryPolicyStorePlugin, SigUtils.SigListen
}
@Override
- public void onAlterSentryRoleGrantPrivilege(TAlterSentryRoleGrantPrivilegeRequest request,
- Map<TSentryPrivilege, Update> privilegesUpdateMap) throws SentryPluginException {
- Preconditions.checkNotNull(request, "request");
+ public void onAlterSentryRoleGrantPrivilege(String roleName, Set<TSentryPrivilege> privileges,
+ Map<TSentryPrivilege, Update> privilegesUpdateMap) throws SentryPluginException {
+ Preconditions.checkNotNull(roleName, "Role name is NULL");
+ Preconditions.checkNotNull(privilegesUpdateMap, "Privilege MAP NULL");
+ Preconditions.checkNotNull(privileges, "Privilege Set provided is NULL");
+
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("onAlterSentryRoleGrantPrivilege: {}", request); // request.toString() provides all details
+ LOGGER.trace("onAlterSentryRoleGrantPrivilege: {}", roleName, privileges);
}
- if (request.isSetPrivileges()) {
- String roleName = request.getRoleName();
-
- for (TSentryPrivilege privilege : request.getPrivileges()) {
+ if (privileges.size() > 0) {
+ for (TSentryPrivilege privilege : privileges) {
if(!(PrivilegeScope.COLUMN.name().equalsIgnoreCase(privilege.getPrivilegeScope()))) {
PermissionsUpdate update = onAlterSentryGrantPrivilegeCore(new TPrivilegeEntity(TPrivilegeEntityType.ROLE,
roleName), privilege);
@@ -285,7 +284,7 @@ public class SentryPlugin implements SentryPolicyStorePlugin, SigUtils.SigListen
Preconditions.checkNotNull(privileges, "Privilege Set provided is NULL");
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("onAlterSentryUserGrantPrivilege: {}", userName);
+ LOGGER.trace("onAlterSentryUserGrantPrivilege: {}", userName, privileges);
}
if (privileges.size() > 0) {
@@ -349,18 +348,19 @@ public class SentryPlugin implements SentryPolicyStorePlugin, SigUtils.SigListen
}
@Override
- public void onAlterSentryRoleRevokePrivilege(TAlterSentryRoleRevokePrivilegeRequest request,
- Map<TSentryPrivilege, Update> privilegesUpdateMap)
+ public void onAlterSentryRoleRevokePrivilege(String roleName, Set<TSentryPrivilege> privileges,
+ Map<TSentryPrivilege, Update> privilegesUpdateMap)
throws SentryPluginException {
- Preconditions.checkNotNull(request, "request");
+ Preconditions.checkNotNull(roleName, "Role name is NULL");
+ Preconditions.checkNotNull(privilegesUpdateMap, "Privilege MAP NULL");
+ Preconditions.checkNotNull(privileges, "Privilege Set provided is NULL");
+
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("onAlterSentryRoleRevokePrivilege: {}", request); // request.toString() provides all details
+ LOGGER.trace("onAlterSentryRoleRevokePrivilege: {}", roleName, privileges);
}
- if (request.isSetPrivileges()) {
- String roleName = request.getRoleName();
-
- for (TSentryPrivilege privilege : request.getPrivileges()) {
+ if (privileges.size() > 0) {
+ for (TSentryPrivilege privilege : privileges) {
if(!("COLUMN".equalsIgnoreCase(privilege.getPrivilegeScope()))) {
PermissionsUpdate update = onAlterSentryRevokePrivilegeCore(new TPrivilegeEntity(TPrivilegeEntityType.ROLE,
roleName), privilege);
@@ -385,7 +385,7 @@ public class SentryPlugin implements SentryPolicyStorePlugin, SigUtils.SigListen
Preconditions.checkNotNull(privileges, "Privilege Set provided is NULL");
if (LOGGER.isTraceEnabled()) {
- LOGGER.trace("onAlterSentryUserRevokePrivilege: {}", userName); // request.toString() provides all details
+ LOGGER.trace("onAlterSentryUserRevokePrivilege: {}", userName, privileges);
}
if (privileges.size() > 0) {
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryMetrics.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryMetrics.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryMetrics.java
index 5424bff..232a979 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryMetrics.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryMetrics.java
@@ -112,6 +112,8 @@ public final class SentryMetrics {
name(SentryPolicyStoreProcessor.class, "list-privileges-for-provider"));
final Timer listPrivilegesByAuthorizableTimer = METRIC_REGISTRY.timer(
name(SentryPolicyStoreProcessor.class, "list-privileges-by-authorizable"));
+ final Timer notificationProcessTimer = METRIC_REGISTRY.timer(
+ name(SentryPolicyStoreProcessor.class, "process-hsm-notification"));
/**
* Return a Timer with name.
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
index 7f97ff7..5aef620 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/api/service/thrift/SentryPolicyStoreProcessor.java
@@ -22,6 +22,8 @@ package org.apache.sentry.api.service.thrift;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -32,6 +34,8 @@ import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType;
+import org.apache.sentry.SentryOwnerInfo;
import org.apache.sentry.api.common.ThriftConstants;
import org.apache.sentry.core.common.exception.SentryUserException;
import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
@@ -68,6 +72,7 @@ import static com.codahale.metrics.MetricRegistry.name;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -81,6 +86,10 @@ import static org.apache.sentry.hdfs.Updateable.Update;
public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
private static final Logger LOGGER = Logger.getLogger(SentryPolicyStoreProcessor.class);
private static final Logger AUDIT_LOGGER = Logger.getLogger(Constants.AUDIT_LOGGER_NAME);
+ private static final Map<TSentryObjectOwnerType, SentryEntityType> mapOwnerType = ImmutableMap.of(
+ TSentryObjectOwnerType.ROLE, SentryEntityType.ROLE,
+ TSentryObjectOwnerType.USER, SentryEntityType.USER
+ );
private final String name;
private final Configuration conf;
@@ -257,7 +266,7 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
Preconditions.checkState(sentryPlugins.size() <= 1);
Map<TSentryPrivilege, Update> privilegesUpdateMap = new HashMap<>();
for (SentryPolicyStorePlugin plugin : sentryPlugins) {
- plugin.onAlterSentryRoleGrantPrivilege(request, privilegesUpdateMap);
+ plugin.onAlterSentryRoleGrantPrivilege(request.getRoleName(), request.getPrivileges(), privilegesUpdateMap);
}
if (!privilegesUpdateMap.isEmpty()) {
@@ -335,7 +344,7 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
Preconditions.checkState(sentryPlugins.size() <= 1);
Map<TSentryPrivilege, Update> privilegesUpdateMap = new HashMap<>();
for (SentryPolicyStorePlugin plugin : sentryPlugins) {
- plugin.onAlterSentryRoleRevokePrivilege(request, privilegesUpdateMap);
+ plugin.onAlterSentryRoleRevokePrivilege(request.getRoleName(), request.getPrivileges(), privilegesUpdateMap);
}
if (!privilegesUpdateMap.isEmpty()) {
@@ -1342,6 +1351,179 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
return response;
}
+ @Override
+ public TSentryHmsEventNotificationResponse sentry_notify_hms_event
+ (TSentryHmsEventNotification request) throws TException{
+ TSentryHmsEventNotificationResponse response = new TSentryHmsEventNotificationResponse();
+ final Timer.Context timerContext = sentryMetrics.notificationProcessTimer.time();
+ EventType eventType = EventType.valueOf(request.getEventType());
+ try {
+ switch (eventType) {
+ case CREATE_DATABASE:
+ case CREATE_TABLE:
+ // Wait till Sentry server processes HMS Notification Event.
+ if(request.getId() > 0) {
+ response.setId(syncEventId(request.getId()));
+ }
+ //Grant privilege to the owner.
+ grantOwnerPrivilege(request);
+ break;
+ case DROP_DATABASE:
+ case DROP_TABLE:
+ // Wait till Sentry server processes HMS Notification Event.
+ if(request.getId() > 0) {
+ response.setId(syncEventId(request.getId()));
+ }
+ // Owner privileges for the database and tables that are dropped are cleaned-up when
+ // sentry fetches and process the DROP_DATABASE and DROP_TABLE notifications.
+ break;
+ case ALTER_TABLE:
+ /* Alter table event is notified to sentry when either of below is observed.
+ together.
+ 1. Owner Update
+ 2. Table Rename
+ */
+ // Wait till Sentry server processes HMS Notification Event.
+ if(request.getId() > 0) {
+ response.setId(syncEventId(request.getId()));
+ }
+ // Owner is updated. There is no need to wait till Sentry processes HMS Notification Event.
+ // Revoke owner privilege from old owners and grant one to the new owner.
+ updateOwnerPrivilege(request);
+ break;
+ default:
+ LOGGER.info("Processing HMS Event of Type: " + eventType.toString() + " skipped");
+ }
+ response.setStatus(Status.OK());
+ } catch (SentryNoSuchObjectException e) {
+ String msg = request.getOwnerType().toString() + ": " + request.getOwnerName() + " doesn't exist";
+ LOGGER.error(msg, e);
+ response.setStatus(Status.NoSuchObject(msg, e));
+ } catch (SentryInvalidInputException e) {
+ LOGGER.error(e.getMessage(), e);
+ response.setStatus(Status.InvalidInput(e.getMessage(), e));
+ } catch (SentryThriftAPIMismatchException e) {
+ LOGGER.error(e.getMessage(), e);
+ response.setStatus(Status.THRIFT_VERSION_MISMATCH(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));
+ } finally {
+ timerContext.stop();
+ }
+ return response;
+ }
+
+ /**
+ * Grants owner privilege to an authorizable.
+ *
+ * Privilege is granted based on the information in TSentryHmsEventNotification
+ * @param request TSentryHmsEventNotification
+ * @throws Exception when there an exception while sending/processing the request.
+ */
+ private void grantOwnerPrivilege(TSentryHmsEventNotification request) throws Exception {
+ if (Strings.isNullOrEmpty(request.getOwnerName()) || (request.getOwnerType().getValue() == 0)) {
+ LOGGER.debug(String.format("Owner Information not provided for Operation: [%s], Not adding owner privilege for" +
+ " object: [%s].[%s]", request.getEventType(), request.getAuthorizable().getDb(),
+ request.getAuthorizable().getTable()));
+ return;
+ }
+
+ TSentryPrivilege ownerPrivilege = constructOwnerPrivilege(request.getAuthorizable());
+ if (ownerPrivilege == null) {
+ LOGGER.debug("Owner privilege is not added");
+ return;
+ }
+
+ SentryEntityType entityType = getSentryEntityType(request.getOwnerType());
+ if (entityType == null) {
+ String error = "Invalid owner type : " + request.getEventType();
+ LOGGER.error(error);
+ throw new SentryInvalidInputException(error);
+ }
+
+ Preconditions.checkState(sentryPlugins.size() <= 1);
+ Set<TSentryPrivilege> privSet = Collections.singleton(ownerPrivilege);
+ Map<TSentryPrivilege, Update> privilegesUpdateMap = new HashMap<>();
+ switch (request.getOwnerType()) {
+ case ROLE:
+ for (SentryPolicyStorePlugin plugin : sentryPlugins) {
+ plugin.onAlterSentryRoleGrantPrivilege(request.getOwnerName(), privSet, privilegesUpdateMap);
+ }
+ break;
+ case USER:
+ for (SentryPolicyStorePlugin plugin : sentryPlugins) {
+ plugin.onAlterSentryUserGrantPrivilege(request.getOwnerName(), privSet, privilegesUpdateMap);
+ }
+ break;
+ default:
+ LOGGER.error("Invalid owner Type");
+ }
+ // Grants owner privilege to the entity
+ sentryStore.alterSentryGrantOwnerPrivilege(request.getOwnerName(), entityType,
+ ownerPrivilege, privilegesUpdateMap.get(ownerPrivilege));
+ //TODO Implement notificationHandlerInvoker API for granting user priv and invoke it.
+ //TODO Implement Audit Log API's and invoke them here.
+ }
+
+ /**
+ * Alters owner privilege of an authorizable.
+ *
+ * Revoke all the owner privileges on the authorizable and grants new owner privilege.
+ * @param request Sentry HMS Event Notification
+ * @throws Exception when there an exception while sending/processing the request.
+ */
+ private void updateOwnerPrivilege(TSentryHmsEventNotification request) throws Exception {
+ if (Strings.isNullOrEmpty(request.getOwnerName()) || (request.getOwnerType().getValue() == 0)) {
+ LOGGER.debug(String.format("Owner Information not provided for Operation: [%s], Not revoking owner privilege for" +
+ " object: [%s].[%s]", request.getEventType(), request.getAuthorizable().getDb(),
+ request.getAuthorizable().getTable()));
+ return;
+ }
+
+ TSentryPrivilege ownerPrivilege = constructOwnerPrivilege(request.getAuthorizable());
+ if (ownerPrivilege == null) {
+ LOGGER.debug("Owner privilege is not added");
+ return;
+ }
+
+ SentryEntityType entityType = getSentryEntityType(request.getOwnerType());
+ if(entityType == null ) {
+ String error = "Invalid owner type : " + request.getEventType();
+ LOGGER.error(error);
+ throw new SentryInvalidInputException(error);
+ }
+
+ Set<TSentryPrivilege> privSet = Collections.singleton(ownerPrivilege);
+ Preconditions.checkState(sentryPlugins.size() <= 1);
+ Map<TSentryPrivilege, Update> privilegesUpdateMap = new HashMap<>();
+ List<Update> updateList = new ArrayList<>();
+ List<SentryOwnerInfo> ownerInfoList = sentryStore.listOwnersByAuthorizable(request.getAuthorizable());
+ // Creating updates for deleting all the old owner privileges
+ // There should only one owner privilege for an authorizable but the current schema
+ // doesn't have constraints to limit it. It is possible to have multiple owners for an authorizable (which is unlikely)
+ // This logic makes sure of revoking all the owner privilege.
+ for (SentryOwnerInfo ownerInfo : ownerInfoList) {
+ if (ownerInfo.getOwnerType() == SentryEntityType.USER) {
+ for (SentryPolicyStorePlugin plugin : sentryPlugins) {
+ plugin.onAlterSentryUserRevokePrivilege(ownerInfo.getOwnerName(), privSet, privilegesUpdateMap);
+ updateList.add(privilegesUpdateMap.get(ownerPrivilege));
+ }
+ } else if (ownerInfo.getOwnerType() == SentryEntityType.ROLE) {
+ for (SentryPolicyStorePlugin plugin : sentryPlugins) {
+ plugin.onAlterSentryRoleRevokePrivilege(request.getOwnerName(), privSet, privilegesUpdateMap);
+ updateList.add(privilegesUpdateMap.get(ownerPrivilege));
+ }
+ }
+ }
+ // Revokes old owner privileges and grants owner privilege for new owner.
+ sentryStore.updateOwnerPrivilege(request.getAuthorizable(), request.getOwnerName(),
+ entityType, updateList);
+ //TODO Implement notificationHandlerInvoker API for granting user priv and invoke it.
+ //TODO Implement Audit Log API's and invoke them here.
+ }
+
/**
* This API constructs (@Link TSentryPrivilege} for authorizable provided
* based on the configurations.
@@ -1352,7 +1534,7 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
TSentryPrivilege constructOwnerPrivilege(TSentryAuthorizable authorizable) {
Boolean isOwnerPrivEnabled = conf.getBoolean(ServerConfig.SENTRY_ENABLE_OWNER_PRIVILEGES,
ServerConfig.SENTRY_ENABLE_OWNER_PRIVILEGES_DEFAULT);
- if(isOwnerPrivEnabled == false) {
+ if(!isOwnerPrivEnabled) {
return null;
}
if(Strings.isNullOrEmpty(authorizable.getDb())) {
@@ -1366,6 +1548,9 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
ownerPrivilege.setDbName(authorizable.getDb());
if(!Strings.isNullOrEmpty(authorizable.getTable())) {
ownerPrivilege.setTableName(authorizable.getTable());
+ ownerPrivilege.setPrivilegeScope("TABLE");
+ } else {
+ ownerPrivilege.setPrivilegeScope("DATABASE");
}
if(privilegeWithGrantOption) {
ownerPrivilege.setGrantOption(TSentryGrantOption.TRUE);
@@ -1374,12 +1559,34 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface {
return ownerPrivilege;
}
- @Override
- public TSentryHmsEventNotificationResponse sentry_notify_hms_event
- (TSentryHmsEventNotification request) throws TException{
- TSentryHmsEventNotificationResponse response = new TSentryHmsEventNotificationResponse();
- //TODO This API has to be implemented.
- response.setStatus(Status.OK());
- return response;
+ /**
+ *
+ * @param ownerType
+ * @return SentryEntityType if input was valid, otherwise returns null
+ * @throws Exception
+ */
+ private SentryEntityType getSentryEntityType(TSentryObjectOwnerType ownerType) throws Exception {
+ return mapOwnerType.get(ownerType);
+ }
+
+ /**
+ * Syncronizes with the eventId processed by sentry
+ * @param eventId
+ * @return current counter value that should be no smaller then the requested
+ * value, returns 0 if there were an exception.
+ */
+ long syncEventId(long eventId) {
+ try {
+ return sentryStore.getCounterWait().waitFor(eventId);
+ } catch (InterruptedException e) {
+ String msg = String.format("wait request for id %d is interrupted",
+ eventId);
+ LOGGER.error(msg, e);
+ Thread.currentThread().interrupt();
+ } catch (TimeoutException e) {
+ String msg = String.format("timed out wait request for id %d", eventId);
+ LOGGER.warn(msg, e);
+ }
+ return 0;
}
}
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/SentryPolicyStorePlugin.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/SentryPolicyStorePlugin.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/SentryPolicyStorePlugin.java
index 52f25dc..e27e1db 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/SentryPolicyStorePlugin.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/SentryPolicyStorePlugin.java
@@ -24,8 +24,6 @@ import org.apache.sentry.core.common.exception.SentryUserException;
import org.apache.sentry.provider.db.service.persistent.SentryStore;
import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddGroupsRequest;
import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteGroupsRequest;
-import org.apache.sentry.api.service.thrift.TAlterSentryRoleGrantPrivilegeRequest;
-import org.apache.sentry.api.service.thrift.TAlterSentryRoleRevokePrivilegeRequest;
import org.apache.sentry.api.service.thrift.TDropPrivilegesRequest;
import org.apache.sentry.api.service.thrift.TDropSentryRoleRequest;
import org.apache.sentry.api.service.thrift.TRenamePrivilegesRequest;
@@ -62,10 +60,24 @@ public interface SentryPolicyStorePlugin {
Update onAlterSentryRoleDeleteGroups(TAlterSentryRoleDeleteGroupsRequest tRequest) throws SentryPluginException;
- void onAlterSentryRoleGrantPrivilege(TAlterSentryRoleGrantPrivilegeRequest tRequest,
- Map<TSentryPrivilege, Update> privilegesUpdateMap) throws SentryPluginException;
+ /**
+ * Used to create an update when privileges are granted to owner who is a Role
+ * @param roleName
+ * @param privileges
+ * @param privilegesUpdateMap
+ * @throws SentryPluginException
+ */
+ void onAlterSentryRoleGrantPrivilege(String roleName, Set<TSentryPrivilege> privileges,
+ Map<TSentryPrivilege, Update> privilegesUpdateMap) throws SentryPluginException;
- void onAlterSentryRoleRevokePrivilege(TAlterSentryRoleRevokePrivilegeRequest tRequest,
+ /**
+ * Used to create an update when privileges are revoked from owner who is a role
+ * @param roleName
+ * @param privileges
+ * @param privilegesUpdateMap
+ * @throws SentryPluginException
+ */
+ void onAlterSentryRoleRevokePrivilege(String roleName, Set<TSentryPrivilege> privileges,
Map<TSentryPrivilege, Update> privilegesUpdateMap) throws SentryPluginException;
/**
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/CounterWait.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/CounterWait.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/CounterWait.java
index d8c8297..ea2f77d 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/CounterWait.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/CounterWait.java
@@ -54,7 +54,7 @@ import java.util.concurrent.atomic.AtomicLong;
* updater threads.
*/
@ThreadSafe
-public final class CounterWait {
+public class CounterWait {
// Implementation notes.
//
// The implementation is based on:
@@ -102,7 +102,7 @@ public final class CounterWait {
/**
* Create an instance of CounterWait object that will timeout during wait
- * @param waitTimeout maximum time in seconds to wait for counter
+ * @param waitTimeoutSec maximum time in seconds to wait for counter
*/
public CounterWait(long waitTimeoutSec) {
this(waitTimeoutSec, TimeUnit.SECONDS);
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index d673239..27b8876 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -42,6 +42,7 @@ import javax.jdo.Query;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.SentryOwnerInfo;
import org.apache.sentry.core.common.exception.SentryAccessDeniedException;
import org.apache.sentry.core.common.exception.SentryAlreadyExistsException;
import org.apache.sentry.core.common.exception.SentryGrantDeniedException;
@@ -199,6 +200,7 @@ public class SentryStore {
*/
private final CounterWait counterWait;
+ private final boolean ownerPrivilegeWithGrant;
public static Properties getDataNucleusProperties(Configuration conf)
throws SentrySiteConfigurationException, IOException {
Properties prop = new Properties();
@@ -283,6 +285,8 @@ public class SentryStore {
long notificationTimeout = conf.getInt(ServerConfig.SENTRY_NOTIFICATION_SYNC_TIMEOUT_MS,
ServerConfig.SENTRY_NOTIFICATION_SYNC_TIMEOUT_DEFAULT);
counterWait = new CounterWait(notificationTimeout, TimeUnit.MILLISECONDS);
+ ownerPrivilegeWithGrant = conf.getBoolean(ServerConfig.SENTRY_OWNER_PRIVILEGE_WITH_GRANT,
+ ServerConfig.SENTRY_OWNER_PRIVILEGE_WITH_GRANT_DEFAULT);
}
public void setPersistUpdateDeltas(boolean persistUpdateDeltas) {
@@ -793,7 +797,8 @@ public class SentryStore {
if(type == SentryEntityType.ROLE) {
throw noSuchRole(entityName);
} else if(type == SentryEntityType.USER) {
- throw noSuchUser(entityName);
+ // User might not exist. Creating one.
+ mEntity = new MSentryUser(entityName, System.currentTimeMillis(), Sets.newHashSet());
}
}
@@ -802,8 +807,9 @@ public class SentryStore {
throw new SentryInvalidInputException("cannot grant URI privileges to Null or EMPTY location");
}
- if (!isNULL(privilege.getColumnName()) || !isNULL(privilege.getTableName())
- || !isNULL(privilege.getDbName())) {
+ if ((!isNULL(privilege.getColumnName()) || !isNULL(privilege.getTableName())
+ || !isNULL(privilege.getDbName()))
+ && !AccessConstants.OWNER.equalsIgnoreCase(privilege.getAction())) {
// If Grant is for ALL and Either INSERT/SELECT already exists..
// need to remove it and GRANT ALL..
if (AccessConstants.ALL.equalsIgnoreCase(privilege.getAction())
@@ -878,6 +884,36 @@ public class SentryStore {
}
/**
+ * Alter a give sentry user/role to set owner privilege, as well as persist the corresponding
+ * permission change to MSentryPermChange table in a single transaction.
+ * Creates User, if it is not already there.
+ * Internally calls alterSentryGrantPrivilege.
+ * @param entityName Entity name to which permissions should be granted.
+ * @param entityType Entity Type
+ * @param privilege Privilege to be granted
+ * @param update DeltaTransactionBlock
+ * @throws Exception
+ */
+ public void alterSentryGrantOwnerPrivilege(final String entityName, SentryEntityType entityType,
+ final TSentryPrivilege privilege,
+ final Update update) throws Exception {
+ execute(update, pm -> {
+ pm.setDetachAllOnCommit(false); // No need to detach objects
+ String trimmedEntityName = trimAndLower(entityName);
+
+ // Alter sentry Role and grant Privilege.
+ MSentryPrivilege mPrivilege = alterSentryGrantPrivilegeCore(pm, entityType,
+ trimmedEntityName, privilege);
+
+ if (mPrivilege != null) {
+ // update the privilege to be the one actually updated.
+ convertToTSentryPrivilege(mPrivilege, privilege);
+ }
+ return null;
+ });
+ }
+
+ /**
* Alter a given sentry user to grant a set of privileges, as well as persist the
* corresponding permission change to MSentryPermChange table in a single transaction.
* Internally calls alterSentryGrantPrivilege.
@@ -1092,7 +1128,7 @@ public class SentryStore {
privilegeGraph.add(mFalse);
}
// Get the privilege graph
- populateChildren(pm, SentryEntityType.ROLE, Sets.newHashSet(entityName), mPrivilege, privilegeGraph);
+ populateChildren(pm, type, Sets.newHashSet(entityName), mPrivilege, privilegeGraph);
for (MSentryPrivilege childPriv : privilegeGraph) {
revokePrivilege(pm, tPrivilege, mEntity, childPriv);
}
@@ -1933,6 +1969,46 @@ public class SentryStore {
return result;
});
}
+ /**
+ * List the Owner privileges for an authorizable
+ * @param pm persistance manager
+ * @param authHierarchy Authorizable
+ * @return privilege list
+ * @throws Exception
+ */
+ private List<MSentryPrivilege> getMSentryOwnerPrivilegesByAuth(PersistenceManager pm,
+ final TSentryAuthorizable
+ authHierarchy) throws Exception {
+ Query query = pm.newQuery(MSentryPrivilege.class);
+ QueryParamBuilder paramBuilder = QueryParamBuilder.newQueryParamBuilder();
+ if (authHierarchy.getServer() != null) {
+ paramBuilder.add(SERVER_NAME, authHierarchy.getServer());
+ if (authHierarchy.getDb() != null) {
+ paramBuilder.add(DB_NAME, authHierarchy.getDb()).addNull(URI);
+ if (authHierarchy.getTable() != null) {
+ paramBuilder.add(TABLE_NAME, authHierarchy.getTable());
+ } else {
+ paramBuilder.addNull(TABLE_NAME);
+ }
+ } else if (authHierarchy.getUri() != null) {
+ paramBuilder.addNotNull(URI)
+ .addNull(DB_NAME)
+ .addCustomParam("(:authURI.startsWith(URI))", "authURI", authHierarchy.getUri());
+ } else {
+ paramBuilder.addNull(DB_NAME)
+ .addNull(URI);
+ }
+ paramBuilder.add(ACTION, AccessConstants.OWNER);
+ } else {
+ // if no server, then return empty result
+ return Collections.emptyList();
+ }
+ query.setFilter(paramBuilder.toString());
+ @SuppressWarnings("unchecked")
+ List<MSentryPrivilege> result = (List<MSentryPrivilege>) query.
+ executeWithMap(paramBuilder.getArguments());
+ return result;
+ }
private Set<MSentryPrivilege> getMSentryPrivilegesByUserName(String userName)
throws Exception {
@@ -1997,6 +2073,31 @@ public class SentryStore {
}
/**
+ * List the Owners for an authorizable
+ * @param authorizable Authorizable
+ * @return List of owner for an authorizable
+ * @throws Exception
+ */
+ public List<SentryOwnerInfo> listOwnersByAuthorizable(TSentryAuthorizable authorizable)
+ throws Exception {
+ List<SentryOwnerInfo> ownerInfolist = new ArrayList<>();
+ return tm.executeTransaction(
+ pm -> {
+ List<MSentryPrivilege> mSentryPrivileges =
+ getMSentryOwnerPrivilegesByAuth(pm, authorizable);
+ for (MSentryPrivilege priv : mSentryPrivileges) {
+ for (PrivilegeEntity user : priv.getUsers()) {
+ ownerInfolist.add(new SentryOwnerInfo(user.getType(), user.getEntityName()));
+ }
+ for (PrivilegeEntity role : priv.getRoles()) {
+ ownerInfolist.add(new SentryOwnerInfo(role.getType(), role.getEntityName()));
+ }
+ }
+ return ownerInfolist;
+ });
+ }
+
+ /**
* Get all privileges associated with the authorizable and input users
* @param userNames the users to get their privileges
* @param authHierarchy the authorizables
@@ -2577,6 +2678,78 @@ public class SentryStore {
}
/**
+ * Updates the owner privileges by revoking owner privileges to an authorizable and adding new
+ * privilege based on the arguments provided.
+ * @param tAuthorizable Authorizable to which owner privilege should be granted.
+ * @param ownerName
+ * @param entityType
+ * @param updates Delta Updates.
+ * @throws Exception
+ */
+ public synchronized void updateOwnerPrivilege(final TSentryAuthorizable tAuthorizable,
+ String ownerName, SentryEntityType entityType,
+ final List<Update> updates) throws Exception {
+ execute(updates, pm -> {
+ if(entityType == null) {
+ LOGGER.info("Invalid Entity Type");
+ }
+ pm.setDetachAllOnCommit(false); // No need to detach objects
+ TSentryPrivilege tOwnerPrivilege = toSentryPrivilege(tAuthorizable);
+ tOwnerPrivilege.setAction(AccessConstants.OWNER);
+
+ revokeOwnerPrivilegesCore(pm, tAuthorizable);
+
+ try {
+ if(ownerPrivilegeWithGrant) {
+ tOwnerPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+ }
+ //Granting the privilege.
+ alterSentryGrantPrivilegeCore(pm, entityType, ownerName, tOwnerPrivilege);
+ return null;
+ } catch (JDODataStoreException e) {
+ throw new SentryInvalidInputException("Failed to grant owner privilege on Authorizable : " +
+ tAuthorizable.toString() + " to " + entityType.toString() + ": " + ownerName + " "
+ + e.getMessage());
+ }
+ });
+ }
+
+ /**
+ * Revokes all the owner privileges granted to an authorizable
+ * @param tAuthorizable authorizable for which owner privilege should be revoked.
+ * @param updates
+ * @throws Exception
+ */
+ @VisibleForTesting
+ void revokeOwnerPrivileges(final TSentryAuthorizable tAuthorizable, final List<Update> updates)
+ throws Exception{
+ execute(updates, pm -> {
+ pm.setDetachAllOnCommit(false);
+ revokeOwnerPrivilegesCore(pm, tAuthorizable);
+ return null;
+ });
+ }
+
+ public void revokeOwnerPrivilegesCore(PersistenceManager pm, final TSentryAuthorizable tAuthorizable)
+ throws Exception{
+ TSentryPrivilege tOwnerPrivilege = toSentryPrivilege(tAuthorizable);
+ tOwnerPrivilege.setAction(AccessConstants.OWNER);
+
+ // Finding owner privileges and removing them.
+ List<MSentryPrivilege> mOwnerPrivileges = getMSentryPrivileges(tOwnerPrivilege, pm);
+ for(MSentryPrivilege mOwnerPriv : mOwnerPrivileges) {
+ Set<MSentryUser> users;
+ users = mOwnerPriv.getUsers();
+ // Making sure of removing stale users.
+ for (MSentryUser user : users) {
+ user.removePrivilege(mOwnerPriv);
+ persistEntity(pm, SentryEntityType.USER, user);
+ }
+ }
+ pm.deletePersistentAll(mOwnerPrivileges);
+ }
+
+ /**
* Rename the privilege for all roles. Drop the old privilege name and create the new one.
*
* @param oldTAuthorizable the old authorizable name needs to be renamed.
@@ -4469,12 +4642,31 @@ public class SentryStore {
*/
private void execute(Update update,
TransactionBlock<Object> transactionBlock) throws Exception {
- List<TransactionBlock<Object>> tbs = new ArrayList<>(2);
+ execute(update != null ? Collections.singletonList(update) : Collections.emptyList(), transactionBlock);
+ }
- if (persistUpdateDeltas && update != null) {
- tbs.add(new DeltaTransactionBlock(update));
- }
+ /**
+ * Execute multiple delta updates in a single transaction.
+ * Note that this method only applies to TransactionBlock that
+ * does not have any return value.
+ * <p>
+ * Failure in any TransactionBlock would cause the whole transaction
+ * to fail.
+ *
+ * @param updates list of delta updates
+ * @throws Exception
+ */
+ private void execute(List<Update> updates, TransactionBlock<Object> transactionBlock) throws Exception {
+ // Currently this API is used to update the owner privilege. This needs two DeltaTransactionBlock's to record
+ // revoking/granting owner privilege and one TransactionBlock to perform actual permission change.
+ // Default size of tbs is picked accordingly.
+ List<TransactionBlock<Object>> tbs = new ArrayList<>(3);
+ if (persistUpdateDeltas && updates != null && updates.size() > 0) {
+ for (Update update : updates) {
+ tbs.add(new DeltaTransactionBlock(update));
+ }
+ }
tbs.add(transactionBlock);
tm.executeTransactionBlocksWithRetry(tbs);
}
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
index 6bfe872..de4e001 100644
--- a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/api/service/thrift/TestSentryPolicyStoreProcessor.java
@@ -23,11 +23,14 @@ import static org.junit.Assert.assertTrue;
import com.codahale.metrics.Gauge;
import com.google.common.collect.Sets;
import java.util.Set;
+import org.apache.hadoop.hive.metastore.messaging.EventMessage;
+import org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType;
import org.apache.sentry.api.common.ApiConstants;
import org.apache.sentry.api.common.Status;
import org.apache.sentry.api.common.ThriftConstants;
import org.apache.sentry.core.common.exception.SentryInvalidInputException;
import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.provider.db.service.persistent.CounterWait;
import org.apache.sentry.service.common.ServiceConstants;
import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
import org.apache.sentry.provider.db.service.persistent.SentryStore;
@@ -44,11 +47,17 @@ import org.mockito.Mockito;
public class TestSentryPolicyStoreProcessor {
+ private static final String DBNAME = "db1";
+ private static final String TABLENAME = "table1";
+ private static final String OWNER = "owner1";
private Configuration conf;
private static final SentryStore sentryStore = Mockito.mock(SentryStore.class);
+ private static final CounterWait counterWait = Mockito.mock(CounterWait.class);
@Before
- public void setup() {
+ public void setup() throws Exception{
conf = new Configuration(false);
+ //Check behaviour when DB name is not set
+ conf.setBoolean(ServiceConstants.ServerConfig.SENTRY_ENABLE_OWNER_PRIVILEGES, true);
Mockito.when(sentryStore.getRoleCountGauge()).thenReturn(new Gauge< Long >() {
@Override
@@ -98,8 +107,14 @@ public class TestSentryPolicyStoreProcessor {
}
});
+ Mockito.doAnswer((invocation) -> {
+ long id = (long) invocation.getArguments()[0];
+ return id;
+ }).when(counterWait).waitFor(Mockito.anyLong());
-
+ Mockito.doAnswer((invocation) -> {
+ return counterWait;
+ }).when(sentryStore).getCounterWait();
}
@Test(expected=SentrySiteConfigurationException.class)
public void testConfigNotNotificationHandler() throws Exception {
@@ -147,6 +162,7 @@ public class TestSentryPolicyStoreProcessor {
@Test
public void testConstructOwnerPrivilege() throws Exception {
+ conf.setBoolean(ServiceConstants.ServerConfig.SENTRY_ENABLE_OWNER_PRIVILEGES, false);
SentryPolicyStoreProcessor sentryServiceHandler =
new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
conf, sentryStore);
@@ -173,6 +189,7 @@ public class TestSentryPolicyStoreProcessor {
authorizable.setDb("db1");
privilege.setDbName("db1");
privilege.setAction(AccessConstants.OWNER);
+ privilege.setPrivilegeScope("DATABASE");
Assert.assertNotNull(sentryServiceHandler.constructOwnerPrivilege(authorizable));
Assert.assertEquals(privilege, sentryServiceHandler.constructOwnerPrivilege(authorizable));
@@ -181,6 +198,7 @@ public class TestSentryPolicyStoreProcessor {
authorizable.setDb("db1");
authorizable.setTable("tb1");
privilege.setTableName("tb1");
+ privilege.setPrivilegeScope("TABLE");
Assert.assertNotNull(sentryServiceHandler.constructOwnerPrivilege(authorizable));
Assert.assertEquals(privilege, sentryServiceHandler.constructOwnerPrivilege(authorizable));
@@ -193,6 +211,7 @@ public class TestSentryPolicyStoreProcessor {
authorizable = new TSentryAuthorizable("");
authorizable.setDb("db1");
authorizable.setTable("tb1");
+ privilege.setPrivilegeScope("TABLE");
privilege.setGrantOption(TSentryGrantOption.TRUE);
Assert.assertNotNull(sentryServiceHandler.constructOwnerPrivilege(authorizable));
Assert.assertEquals(privilege, sentryServiceHandler.constructOwnerPrivilege(authorizable));
@@ -281,4 +300,106 @@ public class TestSentryPolicyStoreProcessor {
privilege.setAction(action);
return privilege;
}
+
+@Test
+ public void testCreateTableEventProcessing() throws Exception {
+ SentryPolicyStoreProcessor sentryServiceHandler =
+ new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
+ conf, sentryStore);
+ TSentryAuthorizable authorizable = new TSentryAuthorizable();
+ authorizable.setDb(DBNAME);
+ authorizable.setTable(TABLENAME);
+
+ TSentryHmsEventNotification notification = new TSentryHmsEventNotification();
+ notification.setId(1L);
+ notification.setOwnerType(TSentryObjectOwnerType.ROLE);
+ notification.setOwnerName(OWNER);
+ notification.setAuthorizable(authorizable);
+ notification.setEventType(EventMessage.EventType.CREATE_TABLE.toString());
+
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ TSentryPrivilege ownerPrivilege = sentryServiceHandler.constructOwnerPrivilege(authorizable);
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).alterSentryGrantOwnerPrivilege(OWNER, SentryEntityType.ROLE, ownerPrivilege, null);
+
+ notification.setOwnerType(TSentryObjectOwnerType.USER);
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ //Verify Sentry Store is invoked to grant privilege.
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).alterSentryGrantOwnerPrivilege(OWNER, SentryEntityType.USER, ownerPrivilege, null);
+ }
+
+
+ @Test
+ public void testCreateDatabaseEventProcessing() throws Exception {
+
+ SentryPolicyStoreProcessor sentryServiceHandler =
+ new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
+ conf, sentryStore);
+ TSentryAuthorizable authorizable = new TSentryAuthorizable();
+ authorizable.setDb(DBNAME);
+
+ TSentryHmsEventNotification notification = new TSentryHmsEventNotification();
+ notification.setId(1L);
+ notification.setOwnerType(TSentryObjectOwnerType.ROLE);
+ notification.setOwnerName(OWNER);
+ notification.setAuthorizable(authorizable);
+ notification.setEventType(EventType.CREATE_DATABASE.toString());
+
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ //Verify Sentry Store is invoked to grant privilege.
+ TSentryPrivilege ownerPrivilege = sentryServiceHandler.constructOwnerPrivilege(authorizable);
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).alterSentryGrantOwnerPrivilege(OWNER, SentryEntityType.ROLE, ownerPrivilege, null);
+
+ notification.setOwnerType(TSentryObjectOwnerType.USER);
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ //Verify Sentry Store is invoked to grant privilege.
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).alterSentryGrantOwnerPrivilege(OWNER, SentryEntityType.USER, ownerPrivilege, null);
+ }
+
+ @Test
+ public void testAlterTableEventProcessing() throws Exception {
+
+ SentryPolicyStoreProcessor sentryServiceHandler =
+ new SentryPolicyStoreProcessor(ApiConstants.SentryPolicyServiceConstants.SENTRY_POLICY_SERVICE_NAME,
+ conf, sentryStore);
+ TSentryAuthorizable authorizable = new TSentryAuthorizable();
+ authorizable.setDb(DBNAME);
+ authorizable.setTable(TABLENAME);
+
+ TSentryHmsEventNotification notification = new TSentryHmsEventNotification();
+ notification.setId(1L);
+ notification.setOwnerType(TSentryObjectOwnerType.ROLE);
+ notification.setOwnerName(OWNER);
+ notification.setAuthorizable(authorizable);
+ notification.setEventType(EventType.ALTER_TABLE.toString());
+
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ //Verify Sentry Store is invoked to grant privilege.
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).updateOwnerPrivilege(Mockito.eq(authorizable), Mockito.eq(OWNER), Mockito.eq(SentryEntityType.ROLE),
+ Mockito.anyList());
+
+
+ notification.setOwnerType(TSentryObjectOwnerType.USER);
+ sentryServiceHandler.sentry_notify_hms_event(notification);
+
+ //Verify Sentry Store is invoked to grant privilege.
+ Mockito.verify(
+ sentryStore, Mockito.times(1)
+ ).updateOwnerPrivilege(Mockito.eq(authorizable), Mockito.eq(OWNER), Mockito.eq(SentryEntityType.ROLE),
+ Mockito.anyList());
+ }
}
http://git-wip-us.apache.org/repos/asf/sentry/blob/4d9bc9ce/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
index c056446..51048bc 100644
--- a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
@@ -43,6 +43,7 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.alias.CredentialProvider;
import org.apache.hadoop.security.alias.CredentialProviderFactory;
import org.apache.hadoop.security.alias.UserProvider;
+import org.apache.sentry.SentryOwnerInfo;
import org.apache.sentry.core.common.exception.SentryAccessDeniedException;
import org.apache.sentry.core.common.exception.SentryInvalidInputException;
import org.apache.sentry.core.model.db.AccessConstants;
@@ -1976,6 +1977,209 @@ public class TestSentryStore extends org.junit.Assert {
}
/**
+ * Grants owner privileges to role/user and updates the owner
+ * and makes sure that the owner privilege is updated.
+ * @throws Exception
+ */
+ @Test
+ public void testUpdateOwnerPrivilege() throws Exception {
+ String roleName1 = "list-privs-r1", roleName2 = "list-privs-r2", roleName3 = "list-privs-r3";
+ String userName1 = "user1", userName2 = "user2";
+ String grantor = "g1";
+ List<SentryOwnerInfo> ownerInfoList = null;
+ sentryStore.createSentryRole(roleName1);
+ sentryStore.createSentryRole(roleName2);
+ sentryStore.createSentryRole(roleName3);
+ sentryStore.createSentryUser(userName1);
+ sentryStore.createSentryUser(userName2);
+
+
+ TSentryPrivilege privilege_tbl1 = new TSentryPrivilege();
+ privilege_tbl1.setPrivilegeScope("TABLE");
+ privilege_tbl1.setServerName("server1");
+ privilege_tbl1.setDbName("db1");
+ privilege_tbl1.setTableName("tbl1");
+ privilege_tbl1.setCreateTime(System.currentTimeMillis());
+ privilege_tbl1.setAction("OWNER");
+
+ TSentryAuthorizable tSentryAuthorizable = new TSentryAuthorizable();
+ tSentryAuthorizable.setServer("server1");
+ tSentryAuthorizable.setDb("db1");
+ tSentryAuthorizable.setTable("tbl1");
+
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName1, privilege_tbl1, null);
+
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByRoleName(roleName1)
+ .size());
+ assertEquals(0, sentryStore.getAllTSentryPrivilegesByRoleName(roleName2)
+ .size());
+
+ ownerInfoList = sentryStore.listOwnersByAuthorizable(tSentryAuthorizable);
+ assertEquals(1, ownerInfoList.size());
+ assertEquals(SentryEntityType.ROLE, ownerInfoList.get(0).getOwnerType());
+ assertEquals(roleName1, ownerInfoList.get(0).getOwnerName());
+
+
+ // Change owner from a one role to another role
+ sentryStore.updateOwnerPrivilege(tSentryAuthorizable, roleName2, SentryEntityType.ROLE, null);
+ ownerInfoList = sentryStore.listOwnersByAuthorizable(tSentryAuthorizable);
+ assertEquals(1, ownerInfoList.size());
+ assertEquals(SentryEntityType.ROLE, ownerInfoList.get(0).getOwnerType());
+ assertEquals(roleName2, ownerInfoList.get(0).getOwnerName());
+
+ assertEquals(0, sentryStore.getAllTSentryPrivilegesByRoleName(roleName1)
+ .size());
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByRoleName(roleName2)
+ .size());
+
+ tSentryAuthorizable.setTable("tbl2");
+ TSentryPrivilege privilege_tbl2 = new TSentryPrivilege(privilege_tbl1);
+ privilege_tbl2.setTableName("tbl2");
+
+ // Change owner from a one user to another user
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.USER,userName1, privilege_tbl2, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByUserName(userName1)
+ .size());
+
+
+
+ sentryStore.updateOwnerPrivilege(tSentryAuthorizable, userName2, SentryEntityType.USER, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByUserName(userName2)
+ .size());
+ ownerInfoList = sentryStore.listOwnersByAuthorizable(tSentryAuthorizable);
+ assertEquals(1, ownerInfoList.size());
+ assertEquals(SentryEntityType.USER, ownerInfoList.get(0).getOwnerType());
+ assertEquals(userName2, ownerInfoList.get(0).getOwnerName());
+
+ // Change owner from a user to role
+ sentryStore.updateOwnerPrivilege(tSentryAuthorizable, roleName1, SentryEntityType.ROLE, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByRoleName(roleName1)
+ .size());
+
+ // At this point roleName1 has owner privilege on db1.tb2
+ //Add all privilege to roleName1 and make sure that owner privilege is not effected.
+ TSentryPrivilege privilege_tbl2_all = new TSentryPrivilege(privilege_tbl2);
+ privilege_tbl2_all.setAction(AccessConstants.ALL);
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName1, privilege_tbl2_all, null);
+ // Verify that there are two privileges.
+ assertEquals(2, sentryStore.getAllTSentryPrivilegesByRoleName(roleName1)
+ .size());
+
+
+ tSentryAuthorizable.setTable("tbl3");
+ TSentryPrivilege privilege_tbl3_all = new TSentryPrivilege(privilege_tbl2);
+ privilege_tbl3_all.setAction(AccessConstants.ALL);
+ privilege_tbl3_all.setTableName("tbl3");
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName3, privilege_tbl3_all, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByRoleName(roleName3)
+ .size());
+ TSentryPrivilege privilege_tbl3_owner = new TSentryPrivilege(privilege_tbl3_all);
+ privilege_tbl3_owner.setAction(AccessConstants.OWNER);
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName3, privilege_tbl3_owner, null);
+
+ assertEquals(2, sentryStore.getAllTSentryPrivilegesByRoleName(roleName3)
+ .size());
+ }
+
+ @Test
+ public void testListSentryOwnerPrivilegesByAuthorizable() throws Exception {
+ String roleName1 = "list-privs-r1";
+ String userName1 = "user1";
+ String grantor = "g1";
+ sentryStore.createSentryRole(roleName1);
+ sentryStore.createSentryUser(userName1);
+
+ TSentryPrivilege privilege_tbl1 = new TSentryPrivilege();
+ privilege_tbl1.setPrivilegeScope("TABLE");
+ privilege_tbl1.setServerName("server1");
+ privilege_tbl1.setDbName("db1");
+ privilege_tbl1.setTableName("tbl1");
+ privilege_tbl1.setCreateTime(System.currentTimeMillis());
+ privilege_tbl1.setAction("OWNER");
+ privilege_tbl1.setGrantOption(TSentryGrantOption.TRUE);
+
+ TSentryAuthorizable tSentryAuthorizable = new TSentryAuthorizable();
+ tSentryAuthorizable.setServer("server1");
+ tSentryAuthorizable.setDb("db1");
+ tSentryAuthorizable.setTable("tbl1");
+
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName1, privilege_tbl1, null);
+
+ sentryStore.updateOwnerPrivilege(tSentryAuthorizable, userName1, SentryEntityType.USER, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByUserName(userName1)
+ .size());
+ }
+
+ @Test
+ public void testRevokeOwnerPrivilege() throws Exception {
+
+ String roleName1 = "list-privs-r1";
+ String userName1 = "user1";
+ String grantor = "g1";
+ sentryStore.createSentryRole(roleName1);
+ sentryStore.createSentryUser(userName1);
+
+ TSentryPrivilege privilege_tbl1 = new TSentryPrivilege();
+ privilege_tbl1.setPrivilegeScope("TABLE");
+ privilege_tbl1.setServerName("server1");
+ privilege_tbl1.setDbName("db1");
+ privilege_tbl1.setTableName("tbl1");
+ privilege_tbl1.setCreateTime(System.currentTimeMillis());
+ privilege_tbl1.setAction("OWNER");
+ privilege_tbl1.setGrantOption(TSentryGrantOption.TRUE);
+
+ TSentryAuthorizable tSentryAuthorizable = new TSentryAuthorizable();
+ tSentryAuthorizable.setServer("server1");
+ tSentryAuthorizable.setDb("db1");
+ tSentryAuthorizable.setTable("tbl1");
+
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.ROLE, roleName1, privilege_tbl1, null);
+
+ sentryStore.revokeOwnerPrivileges(tSentryAuthorizable, null);
+ assertEquals(0, sentryStore.getAllTSentryPrivilegesByUserName(userName1)
+ .size());
+ }
+
+ @Test
+ public void testDropUserOnUpdateOwnerPrivilege() throws Exception {
+ String userName1 = "user1", userName2 = "user2";
+ String grantor = "g1";
+ sentryStore.createSentryUser(userName1);
+ sentryStore.createSentryUser(userName2);
+
+
+ TSentryPrivilege privilege_tbl1 = new TSentryPrivilege();
+ privilege_tbl1.setPrivilegeScope("TABLE");
+ privilege_tbl1.setServerName("server1");
+ privilege_tbl1.setDbName("db1");
+ privilege_tbl1.setTableName("tbl1");
+ privilege_tbl1.setCreateTime(System.currentTimeMillis());
+ privilege_tbl1.setAction("OWNER");
+
+ TSentryAuthorizable tSentryAuthorizable = new TSentryAuthorizable();
+ tSentryAuthorizable.setServer("server1");
+ tSentryAuthorizable.setDb("db1");
+ tSentryAuthorizable.setTable("tbl1");
+
+
+ // Change owner from a one user to another user
+ sentryStore.alterSentryGrantPrivilege(grantor, SentryEntityType.USER, userName1, privilege_tbl1, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByUserName(userName1)
+ .size());
+
+
+ sentryStore.updateOwnerPrivilege(tSentryAuthorizable, userName2, SentryEntityType.USER, null);
+ assertEquals(1, sentryStore.getAllTSentryPrivilegesByUserName(userName2)
+ .size());
+
+ try {
+ sentryStore.createSentryUser(userName1);
+ } catch (Exception e) {
+ fail("Exception should not be seen asthe user: " + userName1 + " should have been deleted.");
+ }
+
+ }
+ /**
* Regression test for SENTRY-547 and SENTRY-548
* Use case:
* GRANT INSERT on TABLE tbl1 to ROLE role1