You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ab...@apache.org on 2021/12/03 23:36:47 UTC
[ranger] branch master updated: RANGER-3535: A delegate admin user should be able to add another user with all or subset of permissions they have
This is an automated email from the ASF dual-hosted git repository.
abhay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 695bedd RANGER-3535: A delegate admin user should be able to add another user with all or subset of permissions they have
695bedd is described below
commit 695bedd07b4f58aef4f5747393c06d83c8805438
Author: Abhay Kulkarni <ab...@apache.org>
AuthorDate: Fri Dec 3 15:01:01 2021 -0800
RANGER-3535: A delegate admin user should be able to add another user with all or subset of permissions they have
---
.../model/RangerPolicyResourceSignature.java | 4 +-
.../apache/ranger/biz/RangerPolicyAdminImpl.java | 244 +++++++++++++++++----
2 files changed, 205 insertions(+), 43 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
index c84d0bc..77b274e 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
@@ -175,10 +175,10 @@ public class RangerPolicyResourceSignature {
}
- static class ResourceSerializer {
+ static public class ResourceSerializer {
final RangerPolicyResource _policyResource;
- ResourceSerializer(RangerPolicyResource policyResource) {
+ public ResourceSerializer(RangerPolicyResource policyResource) {
_policyResource = policyResource;
}
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
index 5311a54..6dbc59f 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
@@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.policyengine.PolicyEngine;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
@@ -59,6 +60,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
public class RangerPolicyAdminImpl implements RangerPolicyAdmin {
private static final Log LOG = LogFactory.getLog(RangerPolicyAdminImpl.class);
@@ -176,22 +178,7 @@ public class RangerPolicyAdminImpl implements RangerPolicyAdmin {
@Override
public boolean isDelegatedAdminAccessAllowedForModify(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, Map<String, Object> evalContext) {
- boolean ret = isDelegatedAdminAccessAllowed(policy, user, userGroups, roles, false, evalContext);
- if (ret) {
- // Get old policy from policy-engine
- RangerPolicy oldPolicy = null;
- if (policy.getId() != null) {
- try {
- oldPolicy = serviceDBStore.getPolicy(policy.getId());
- } catch (Exception e) {
- // Ignore
- }
- }
- if (oldPolicy != null) {
- ret = isDelegatedAdminAccessAllowed(oldPolicy, user, userGroups, roles, false, evalContext);
- }
- }
- return ret;
+ return isDelegatedAdminAccessAllowed(policy, user, userGroups, roles, false, evalContext);
}
boolean isDelegatedAdminAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, boolean isRead, Map<String, Object> evalContext) {
@@ -217,46 +204,104 @@ public class RangerPolicyAdminImpl implements RangerPolicyAdmin {
final RangerPolicyRepository matchedRepository = policyEngine.getRepositoryForMatchedZone(policy);
if (matchedRepository != null) {
- // RANGER-3082
- // Convert policy resources to by substituting macros with ASTERISK
- Map<String, RangerPolicyResource> modifiedPolicyResources = getPolicyResourcesWithMacrosReplaced(policy.getResources(), wildcardEvalContext);
- Set<String> accessTypes = getAllAccessTypes(policy, getServiceDef());
+ if (isRead) {
+ Set<String> accessTypes = getAllAccessTypes(policy, getServiceDef());
+ ret = isDelegatedAdminAccessAllowedForPolicy(matchedRepository, policy, user, userGroups, roles, accessTypes, true, evalContext);
+ } else {
+ // Get old policy from policy-engine
+ RangerPolicy oldPolicy = null;
+ if (policy.getId() != null) {
+ try {
+ oldPolicy = serviceDBStore.getPolicy(policy.getId());
+ } catch (Exception e) {
+ LOG.error("Cannot get old policy from DB: policy-id:[" + policy.getId() + "]");
+ }
+ }
- if (LOG.isDebugEnabled()) {
- LOG.debug("Checking admin-access for the access-types:[" + accessTypes + "]");
+ if (oldPolicy != null) {
+ String oldResourceSignature = getResourceSignature(oldPolicy);
+ String newResourceSignature = getResourceSignature(policy);
+
+ if (StringUtils.equals(oldResourceSignature, newResourceSignature)) {
+ Set<String> modifiedAccessTypes = getAllModifiedAccessTypes(oldPolicy, policy, getServiceDef());
+ ret = isDelegatedAdminAccessAllowedForPolicy(matchedRepository, policy, user, userGroups, roles, modifiedAccessTypes, false, evalContext);
+ } else {
+ Set<String> removedAccessTypes = getAllAccessTypes(oldPolicy, getServiceDef());
+ // Ensure that current policy-engine (without current policy) allows old-policy to be modified
+ final boolean isOldPolicyChangeAllowed = isDelegatedAdminAccessAllowedForPolicy(matchedRepository, oldPolicy, user, userGroups, roles, removedAccessTypes, false, evalContext);
+ if (isOldPolicyChangeAllowed) {
+ Set<String> addedAccessTypes = getAllAccessTypes(policy, getServiceDef());
+ ret = isDelegatedAdminAccessAllowedForPolicy(matchedRepository, policy, user, userGroups, roles, addedAccessTypes, false, evalContext);
+ }
+ }
+ } else {
+ LOG.warn("Cannot get unmodified policy with id:[" + policy.getId() + "]. Checking if thi");
+ Set<String> addedAccessTypes = getAllAccessTypes(policy, getServiceDef());
+ ret = isDelegatedAdminAccessAllowedForPolicy(matchedRepository, policy, user, userGroups, roles, addedAccessTypes, false, evalContext);
+ }
}
+ }
+ }
- for (RangerPolicyEvaluator evaluator : matchedRepository.getPolicyEvaluators()) {
- Set<String> allowedAccesses = evaluator.getAllowedAccesses(modifiedPolicyResources, user, userGroups, roles, accessTypes, evalContext);
+ RangerPerfTracer.log(perf);
- if (allowedAccesses == null) {
- continue;
- }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerPolicyAdminImpl.isDelegatedAdminAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + isRead + ", " + evalContext + "): " + ret);
+ }
- boolean isAllowedAccessesModified = accessTypes.removeAll(allowedAccesses);
+ return ret;
+ }
- if (isRead && isAllowedAccessesModified) {
- ret = true;
- break;
- }
+ private boolean isDelegatedAdminAccessAllowedForPolicy(RangerPolicyRepository matchedRepository, RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, Set<String> accessTypes, boolean isRead, Map<String, Object> evalContext) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> RangerPolicyAdminImpl.isDelegatedAdminAccessAllowedForPolicy(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", accessTypes" + accessTypes + ", " + isRead + ", " + evalContext + ")");
+ }
- if (CollectionUtils.isEmpty(accessTypes)) {
- ret = true;
- break;
- }
+ boolean ret = false;
+
+ if (accessTypes == null) {
+ LOG.error("Could not get added access-types for policy-id:[" + policy.getId() + "]");
+ } else if (accessTypes.isEmpty()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No need to check any access-types for delegated admin check");
+ }
+ ret = true;
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Checking admin-access for the access-types:[" + accessTypes + "]");
+ }
+
+ // RANGER-3082
+ // Convert policy resources to by substituting macros with ASTERISK
+ Map<String, RangerPolicyResource> modifiedPolicyResources = getPolicyResourcesWithMacrosReplaced(policy.getResources(), wildcardEvalContext);
+
+ for (RangerPolicyEvaluator evaluator : matchedRepository.getPolicyEvaluators()) {
+ Set<String> allowedAccesses = evaluator.getAllowedAccesses(modifiedPolicyResources, user, userGroups, roles, accessTypes, evalContext);
+
+ if (allowedAccesses == null) {
+ continue;
}
- if (!ret && CollectionUtils.isNotEmpty(accessTypes)) {
- LOG.info("Accesses : " + accessTypes + " are not authorized for the policy:[" + policy.getId() + "] by any of delegated-admin policies");
+
+ boolean isAllowedAccessesModified = accessTypes.removeAll(allowedAccesses);
+
+ if (isRead && isAllowedAccessesModified) {
+ ret = true;
+ break;
}
+ if (CollectionUtils.isEmpty(accessTypes)) {
+ ret = true;
+ break;
+ }
}
+ if (!ret && CollectionUtils.isNotEmpty(accessTypes)) {
+ LOG.info("Accesses : " + accessTypes + " are not authorized for the policy:[" + policy.getId() + "] by any of delegated-admin policies");
+ }
}
- RangerPerfTracer.log(perf);
-
if (LOG.isDebugEnabled()) {
- LOG.debug("<== RangerPolicyAdminImpl.isDelegatedAdminAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + isRead + ", " + evalContext + "): " + ret);
+ LOG.debug("<== RangerPolicyAdminImpl.isDelegatedAdminAccessAllowedForPolicy(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", accessTypes" + accessTypes + ", " + isRead + ", " + evalContext + "): " + ret);
}
return ret;
@@ -733,5 +778,122 @@ public class RangerPolicyAdminImpl implements RangerPolicyAdmin {
return ret;
}
+ private Set<String> getAllModifiedAccessTypes(RangerPolicy oldPolicy, RangerPolicy policy, RangerServiceDef serviceDef) {
+
+ Set<String> ret = new HashSet<>();
+
+ Map<String, Set<String>> oldUserAccesses = new HashMap<>();
+ Map<String, Set<String>> oldGroupAccesses = new HashMap<>();
+ Map<String, Set<String>> oldRoleAccesses = new HashMap<>();
+
+ Map<String, Set<String>> newUserAccesses = new HashMap<>();
+ Map<String, Set<String>> newGroupAccesses = new HashMap<>();
+ Map<String, Set<String>> newRoleAccesses = new HashMap<>();
+
+ collectAccessTypes(oldPolicy, serviceDef, oldUserAccesses, oldGroupAccesses, oldRoleAccesses);
+ collectAccessTypes(policy, serviceDef, newUserAccesses, newGroupAccesses, newRoleAccesses);
+
+ ret.addAll(getAccessTypesDiff(newUserAccesses, oldUserAccesses));
+ ret.addAll(getAccessTypesDiff(newGroupAccesses, oldGroupAccesses));
+ ret.addAll(getAccessTypesDiff(newRoleAccesses, oldRoleAccesses));
+
+ return ret;
+ }
+
+ private void collectAccessTypes(RangerPolicy policy, RangerServiceDef serviceDef, Map<String, Set<String>> userAccesses, Map<String, Set<String>> groupAccesses, Map<String, Set<String>> roleAccesses) {
+ Map<String, Collection<String>> expandedAccesses = ServiceDefUtil.getExpandedImpliedGrants(serviceDef);
+
+ if (MapUtils.isNotEmpty(expandedAccesses)) {
+
+ Integer policyType = policy.getPolicyType() == null ? RangerPolicy.POLICY_TYPE_ACCESS : policy.getPolicyType();
+
+ if (policyType == RangerPolicy.POLICY_TYPE_ACCESS) {
+ collectAccessTypes(expandedAccesses, policy.getPolicyItems(), userAccesses, groupAccesses, roleAccesses);
+ collectAccessTypes(expandedAccesses, policy.getDenyPolicyItems(), userAccesses, groupAccesses, roleAccesses);
+ collectAccessTypes(expandedAccesses, policy.getAllowExceptions(), userAccesses, groupAccesses, roleAccesses);
+ collectAccessTypes(expandedAccesses, policy.getDenyExceptions(), userAccesses, groupAccesses, roleAccesses);
+ } else if (policyType == RangerPolicy.POLICY_TYPE_DATAMASK) {
+ collectAccessTypes(expandedAccesses, policy.getDataMaskPolicyItems(), userAccesses, groupAccesses, roleAccesses);
+ } else if (policyType == RangerPolicy.POLICY_TYPE_ROWFILTER) {
+ collectAccessTypes(expandedAccesses, policy.getRowFilterPolicyItems(), userAccesses, groupAccesses, roleAccesses);
+ } else {
+ LOG.error("Unknown policy-type :[" + policyType + "], returning empty access-type set");
+ }
+ }
+ }
+
+ private void collectAccessTypes(Map<String, Collection<String>> expandedAccesses, List<? extends RangerPolicy.RangerPolicyItem> policyItems, Map<String, Set<String>> userAccesses, Map<String, Set<String>> groupAccesses, Map<String, Set<String>> roleAccesses) {
+ for (RangerPolicy.RangerPolicyItem item : policyItems) {
+
+ List<RangerPolicy.RangerPolicyItemAccess> accesses = item.getAccesses();
+ Set<String> accessTypes = new HashSet<>();
+
+ for (RangerPolicy.RangerPolicyItemAccess access : accesses) {
+ accessTypes.addAll(expandedAccesses.get(access.getType()));
+ }
+
+ for (String user : item.getUsers()) {
+ Set<String> oldAccesses = userAccesses.get(user);
+ if (oldAccesses != null) {
+ oldAccesses.addAll(accessTypes);
+ } else {
+ userAccesses.put(user, accessTypes);
+ }
+ }
+
+ for (String group : item.getGroups()) {
+ Set<String> oldAccesses = groupAccesses.get(group);
+ if (oldAccesses != null) {
+ oldAccesses.addAll(accessTypes);
+ } else {
+ groupAccesses.put(group, accessTypes);
+ }
+ }
+
+ for (String role : item.getRoles()) {
+ Set<String> oldAccesses = roleAccesses.get(role);
+ if (oldAccesses != null) {
+ oldAccesses.addAll(accessTypes);
+ } else {
+ roleAccesses.put(role, accessTypes);
+ }
+ }
+ }
+ }
+
+ private Set<String> getAccessTypesDiff(Map<String, Set<String>> newAccessesMap, Map<String, Set<String>> oldAccessesMap) {
+ Set<String> ret = new HashSet<>();
+
+ for (Map.Entry<String, Set<String>> entry : newAccessesMap.entrySet()) {
+ Set<String> oldAccesses = oldAccessesMap.get(entry.getKey());
+ if (oldAccesses != null) {
+ Collection<String> added = CollectionUtils.subtract(entry.getValue(), oldAccesses);
+ ret.addAll(added);
+ } else {
+ ret.addAll(entry.getValue());
+ }
+ }
+ for (Map.Entry<String, Set<String>> entry : oldAccessesMap.entrySet()) {
+ Set<String> newAccesses = newAccessesMap.get(entry.getKey());
+ if (newAccesses != null) {
+ Collection<String> removed = CollectionUtils.subtract(entry.getValue(), newAccesses);
+ ret.addAll(removed);
+ } else {
+ ret.addAll(entry.getValue());
+ }
+ }
+ return ret;
+ }
+
+ private String getResourceSignature(final RangerPolicy policy) {
+ Map<String, RangerPolicyResourceSignature.ResourceSerializer> resources = new TreeMap<>();
+ for (Map.Entry<String, RangerPolicyResource> entry : policy.getResources().entrySet()) {
+ String resourceName = entry.getKey();
+ RangerPolicyResourceSignature.ResourceSerializer resourceView = new RangerPolicyResourceSignature.ResourceSerializer(entry.getValue());
+ resources.put(resourceName, resourceView);
+ }
+ return resources.toString();
+ }
+
}