This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 7f86e62860664d280888b10b87f33fe5fbf80a70 Author: Madhan Neethiraj <mad...@apache.org> AuthorDate: Mon Sep 11 16:02:42 2023 -0700 RANGER-4403: security-zone validation updated to prevent duplicate resource entries --- .../ranger/plugin/errors/ValidationErrorCode.java | 1 + .../model/RangerPolicyResourceSignature.java | 15 ++++++++++ .../validation/RangerSecurityZoneValidator.java | 15 ++++++++++ .../RangerSecurityZoneValidatorTest.java | 33 ++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java index d8c214c0f..dbf1714c5 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java @@ -124,6 +124,7 @@ public enum ValidationErrorCode { SECURITY_ZONE_VALIDATION_ERR_INTERNAL_ERROR(3045, "Internal Error:[{0}]"), SECURITY_ZONE_VALIDATION_ERR_ZONE_RESOURCE_CONFLICT(3046, "Multiple zones:[{0}] match resource:[{1}]"), SECURITY_ZONE_VALIDATION_ERR_UNEXPECTED_RESOURCES(3047, "Tag service [{0}], with non-empty resources, is associated with security zone"), + SECURITY_ZONE_VALIDATION_ERR_DUPLICATE_RESOURCE_ENTRY(3052, "Resource [{0}] specified more than once in service [{1}]"), //RANGER ROLE Validations ROLE_VALIDATION_ERR_NULL_RANGER_ROLE_OBJECT(4001, "Internal error: RangerRole object passed in was null"), 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 c14811867..cc7713fca 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 @@ -57,6 +57,11 @@ public class RangerPolicyResourceSignature { } } + public RangerPolicyResourceSignature(Map<String, List<String>> resources) { + this(toSignatureString(toPolicyResources(resources))); + } + + /** * Only added for testability. Do not make public * @param string @@ -204,6 +209,16 @@ public class RangerPolicyResourceSignature { return ret; } + private static Map<String, RangerPolicyResource> toPolicyResources(Map<String, List<String>> resources) { + Map<String, RangerPolicyResource> ret = new TreeMap<>(); + + for (Map.Entry<String, List<String>> entry : resources.entrySet()) { + ret.put(entry.getKey(), new RangerPolicyResource(entry.getValue(), false, false)); + } + + return ret; + } + static public class ResourceSerializer { final RangerPolicyResource _policyResource; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java index 970055511..2a1adb397 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java @@ -24,6 +24,7 @@ import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.ranger.plugin.errors.ValidationErrorCode; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerPolicyResourceSignature; import org.apache.ranger.plugin.model.RangerSecurityZone; import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.model.RangerServiceDef; @@ -460,6 +461,8 @@ public class RangerSecurityZoneValidator extends RangerValidator { } else { if (CollectionUtils.isNotEmpty(securityZoneService.getResources())) { // For each resource-spec, verify that it forms valid hierarchy for some policy-type + Set<String> resourceSignatures = new HashSet<>(); + for (Map<String, List<String>> resource : securityZoneService.getResources()) { Set<String> resourceDefNames = resource.keySet(); RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef); @@ -503,6 +506,18 @@ public class RangerSecurityZoneValidator extends RangerValidator { ret = false; } } + + RangerPolicyResourceSignature resourceSignature = new RangerPolicyResourceSignature(resource); + + if (!resourceSignatures.add(resourceSignature.getSignature())) { + ValidationErrorCode error = ValidationErrorCode.SECURITY_ZONE_VALIDATION_ERR_DUPLICATE_RESOURCE_ENTRY; + + failures.add(new ValidationFailureDetailsBuilder().field("security zone resources") + .subField("resources") + .becauseOf(error.getMessage(resource, serviceName)) + .errorCode(error.getErrorCode()).build()); + ret = false; + } } } } diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidatorTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidatorTest.java index 1a1c30517..059ddfb21 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidatorTest.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidatorTest.java @@ -481,6 +481,39 @@ public class RangerSecurityZoneValidatorTest { } } + @Test + public void testValidateDuplicateResourceEntries() throws Exception { + List<HashMap<String, List<String>>> zone1Resources = new ArrayList<>(); + + zone1Resources.add(new HashMap<String, List<String>>() {{ put("database", Arrays.asList("db1")); put("table", Arrays.asList("tbl1")); }}); + zone1Resources.add(new HashMap<String, List<String>>() {{ put("database", Arrays.asList("db1")); put("table", Arrays.asList("tbl1")); }}); + + RangerServiceDef svcDef = getHiveServiceDef(); + RangerService svc = getHiveService(); + RangerSecurityZoneService zone1HiveSvc = new RangerSecurityZoneService(zone1Resources); + + RangerSecurityZone zone1 = new RangerSecurityZone("zone1", Collections.singletonMap(svc.getName(), zone1HiveSvc), null, Arrays.asList("admin"), null, Arrays.asList("auditor"), null, "Zone 1"); + + zone1.setId(1L); + + List<RangerSecurityZone> zones = new ArrayList<RangerSecurityZone>() {{ add(zone1); }}; + + Mockito.when(_store.getServiceByName(svc.getName())).thenReturn(svc); + Mockito.when(_store.getServiceDefByName(svc.getType())).thenReturn(svcDef); + Mockito.when(_store.getSecurityZone(zone1.getId())).thenReturn(zone1); + + try { + rangerSecurityZoneValidator.validate(zone1, RangerValidator.Action.UPDATE); + + Assert.assertFalse("security-zone update should have failed in validation", true); + } catch (Exception excp) { + String failureMessage = excp.getMessage(); + boolean hasResourceConflictError = StringUtils.contains(failureMessage, ValidationErrorCode.SECURITY_ZONE_VALIDATION_ERR_DUPLICATE_RESOURCE_ENTRY.getErrorCode() + ""); + + Assert.assertTrue("validation failure message didn't include expected error code " + ValidationErrorCode.SECURITY_ZONE_VALIDATION_ERR_DUPLICATE_RESOURCE_ENTRY.getErrorCode() + ". Failure message: " + excp.getMessage(), hasResourceConflictError); + } + } + private RangerService getRangerService() { Map<String, String> configs = new HashMap<String, String>(); configs.put("username", "servicemgr");