This is an automated email from the ASF dual-hosted git repository.
vyommani 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 0d17e7efd RANGER-5848: Add constraints to RangerAccessResult (#1320)
0d17e7efd is described below
commit 0d17e7efdd43756e7a3bdff9750fce2a3fba3dd8
Author: Vyom Mani Tiwari <[email protected]>
AuthorDate: Sat Oct 17 17:05:25 2026 +0530
RANGER-5848: Add constraints to RangerAccessResult (#1320)
---
.../plugin/policyengine/RangerAccessResult.java | 73 ++++++++---
.../policyengine/RangerConstraintResult.java | 136 +++++++++++++++++++++
.../ranger/plugin/service/RangerBasePlugin.java | 4 +
.../policyengine/TestRangerAccessResult.java | 99 +++++++++++++++
.../policyengine/TestRangerConstraintResult.java | 98 +++++++++++++++
5 files changed, 391 insertions(+), 19 deletions(-)
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
index 8088b022f..76d942794 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
@@ -24,7 +24,10 @@
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.util.ServiceDefUtil;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -38,24 +41,25 @@ public class RangerAccessResult {
private static final String KEY_ALLOWED_BY_DATASETS = "allowedByDatasets";
private static final String KEY_ALLOWED_BY_PROJECTS = "allowedByProjects";
- private final String serviceName;
- private final RangerServiceDef serviceDef;
- private final RangerAccessRequest request;
-
- private final int policyType; // Really, policy-type for
audit purpose
- private boolean isAccessDetermined;
- private boolean isAllowed;
- private boolean isAuditedDetermined;
- private boolean isAudited;
- private long auditPolicyId = -1;
- private String auditLogId;
- private long policyId = -1;
- private int policyPriority;
- private String zoneName;
- private Long policyVersion;
- private long evaluatedPoliciesCount;
- private String reason;
- private Map<String, Object> additionalInfo;
+ private final String serviceName;
+ private final RangerServiceDef serviceDef;
+ private final RangerAccessRequest request;
+
+ private final int policyType; // Really,
policy-type for audit purpose
+ private boolean isAccessDetermined;
+ private boolean isAllowed;
+ private boolean isAuditedDetermined;
+ private boolean isAudited;
+ private long auditPolicyId = -1;
+ private String auditLogId;
+ private long policyId = -1;
+ private int policyPriority;
+ private String zoneName;
+ private Long policyVersion;
+ private long evaluatedPoliciesCount;
+ private String reason;
+ private Map<String, Object> additionalInfo;
+ private List<RangerConstraintResult> constraints;
public RangerAccessResult(final int policyType, final String serviceName,
final RangerServiceDef serviceDef, final RangerAccessRequest request) {
this.serviceName = serviceName;
@@ -83,6 +87,7 @@ public void setAccessResultFrom(final RangerAccessResult
other) {
this.evaluatedPoliciesCount = other.evaluatedPoliciesCount;
this.reason = other.getReason();
this.additionalInfo = other.additionalInfo == null ? new
HashMap<>() : new HashMap<>(other.additionalInfo);
+ this.constraints = copyConstraints(other.constraints);
}
public void setAuditResultFrom(final RangerAccessResult other) {
@@ -138,6 +143,7 @@ public boolean getIsAllowed() {
public void setIsAllowed(boolean isAllowed) {
if (!isAllowed) {
setIsAccessDetermined(true);
+ this.constraints = null;
}
this.isAllowed = isAllowed;
@@ -408,6 +414,29 @@ public void setAllowedByProjects(Set<String> projects) {
}
}
+ /**
+ * Constraints that matched this request. Empty when access is denied or
nothing matched.
+ */
+ public List<RangerConstraintResult> getConstraints() {
+ return constraints == null ? Collections.emptyList() : constraints;
+ }
+
+ public void setConstraints(List<RangerConstraintResult> constraints) {
+ this.constraints = copyConstraints(constraints);
+ }
+
+ public void addConstraint(RangerConstraintResult constraint) {
+ if (constraint == null) {
+ return;
+ }
+
+ if (constraints == null) {
+ constraints = new ArrayList<>();
+ }
+
+ constraints.add(constraint);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -439,10 +468,16 @@ public StringBuilder toString(StringBuilder sb) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
}
}
- sb.append("}");
+ sb.append("} ");
+
+ sb.append("constraints={").append(getConstraints()).append("}");
sb.append("}");
return sb;
}
+
+ private static List<RangerConstraintResult>
copyConstraints(List<RangerConstraintResult> constraints) {
+ return constraints == null || constraints.isEmpty() ? null : new
ArrayList<>(constraints);
+ }
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerConstraintResult.java
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerConstraintResult.java
new file mode 100644
index 000000000..7e7083fd4
--- /dev/null
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerConstraintResult.java
@@ -0,0 +1,136 @@
+/*
+ * 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.ranger.plugin.policyengine;
+
+import
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher.MatchType;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class RangerConstraintResult {
+ public static final Comparator<RangerConstraintResult>
CONSTRAINT_RESULT_COMPARATOR = new ConstraintResultComparator();
+
+ private final Map<String, Object> parameters;
+ private String constraintName;
+ private long policyId;
+ private Long policyVersion;
+ private int policyPriority;
+ private MatchType matchType;
+
+ public RangerConstraintResult(String constraintName, Map<String, Object>
parameters, long policyId, Long policyVersion, int policyPriority, MatchType
matchType) {
+ this.constraintName = constraintName;
+ this.parameters = parameters == null ? new HashMap<>() : new
HashMap<>(parameters);
+ this.policyId = policyId;
+ this.policyVersion = policyVersion;
+ this.policyPriority = policyPriority;
+ this.matchType = matchType;
+ }
+
+ public String getConstraintName() {
+ return constraintName;
+ }
+
+ public Map<String, Object> getParameters() {
+ return parameters;
+ }
+
+ public long getPolicyId() {
+ return policyId;
+ }
+
+ public Long getPolicyVersion() {
+ return policyVersion;
+ }
+
+ public int getPolicyPriority() {
+ return policyPriority;
+ }
+
+ public MatchType getMatchType() {
+ return matchType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(constraintName, parameters, policyId,
policyVersion, policyPriority, matchType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+
+ RangerConstraintResult other = (RangerConstraintResult) obj;
+
+ return policyId == other.policyId &&
+ policyPriority == other.policyPriority &&
+ Objects.equals(policyVersion, other.policyVersion) &&
+ Objects.equals(constraintName, other.constraintName) &&
+ Objects.equals(matchType, other.matchType) &&
+ Objects.equals(parameters, other.parameters);
+ }
+
+ @Override
+ public String toString() {
+ return "RangerConstraintResult{constraintName=" + constraintName +
+ ", parameters=" + parameters +
+ ", policyId=" + policyId +
+ ", policyVersion=" + policyVersion +
+ ", policyPriority=" + policyPriority +
+ ", matchType=" + matchType +
+ "}";
+ }
+
+ /**
+ * Orders by constraint name, policy priority (higher first), match type,
then policy id.
+ */
+ public static class ConstraintResultComparator implements
Comparator<RangerConstraintResult>, Serializable {
+ @Override
+ public int compare(RangerConstraintResult me, RangerConstraintResult
other) {
+ int ret = compareStrings(me.getConstraintName(),
other.getConstraintName());
+
+ if (ret == 0) {
+ ret = Integer.compare(other.getPolicyPriority(),
me.getPolicyPriority());
+ }
+
+ if (ret == 0) {
+ ret =
RangerPolicyResourceMatcher.MATCH_TYPE_COMPARATOR.compare(me.getMatchType(),
other.getMatchType());
+ }
+
+ if (ret == 0) {
+ ret = Long.compare(me.getPolicyId(), other.getPolicyId());
+ }
+
+ return ret;
+ }
+
+ private static int compareStrings(String me, String other) {
+ return me == null ? (other == null ? 0 : -1) : (other == null ? 1
: me.compareTo(other));
+ }
+ }
+}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index f11f98265..686f5bf04 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -1423,6 +1423,10 @@ private void
updateResultFromChainedResult(RangerAccessResult result, RangerAcce
} else if (policyType == RangerPolicy.POLICY_TYPE_ROWFILTER) {
result.setFilterExpr(chainedResult.getFilterExpr());
}
+
+ if (result.getIsAllowed()) {
+ result.setConstraints(chainedResult.getConstraints());
+ }
}
if (!result.getIsAuditedDetermined() &&
chainedResult.getIsAuditedDetermined()) {
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerAccessResult.java
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerAccessResult.java
new file mode 100644
index 000000000..8fcdbe628
--- /dev/null
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerAccessResult.java
@@ -0,0 +1,99 @@
+/*
+ * 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.ranger.plugin.policyengine;
+
+import
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher.MatchType;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestRangerAccessResult {
+ @Test
+ public void constraintsAreEmptyUntilOneIsAdded() {
+ RangerAccessResult result = newResult();
+
+ assertTrue(result.getConstraints().isEmpty());
+
+ result.addConstraint(null);
+ assertTrue(result.getConstraints().isEmpty());
+
+ RangerConstraintResult constraint = constraint(10L);
+
+ result.addConstraint(constraint);
+
+ assertEquals(Arrays.asList(constraint), result.getConstraints());
+ }
+
+ @Test
+ public void setConstraintsCopiesTheInputList() {
+ RangerAccessResult result = newResult();
+ List<RangerConstraintResult> constraints = new ArrayList<>();
+ RangerConstraintResult constraint = constraint(10L);
+
+ constraints.add(constraint);
+ result.setConstraints(constraints);
+ constraints.clear();
+
+ assertEquals(Arrays.asList(constraint), result.getConstraints());
+
+ result.setConstraints(new ArrayList<>());
+
+ assertTrue(result.getConstraints().isEmpty());
+ }
+
+ @Test
+ public void setAccessResultFromCopiesConstraints() {
+ RangerAccessResult source = newResult();
+ RangerAccessResult copied = newResult();
+ RangerConstraintResult constraint = constraint(10L);
+
+ source.addConstraint(constraint);
+ copied.setAccessResultFrom(source);
+
+ assertEquals(Arrays.asList(constraint), copied.getConstraints());
+ }
+
+ @Test
+ public void denyClearsConstraints() {
+ RangerAccessResult result = newResult();
+
+ result.addConstraint(constraint(10L));
+ result.setIsAllowed(false);
+
+ assertTrue(result.getConstraints().isEmpty());
+
+ result.addConstraint(constraint(11L));
+ result.setIsAllowed(true);
+
+ assertEquals(1, result.getConstraints().size());
+ }
+
+ private static RangerAccessResult newResult() {
+ return new RangerAccessResult(0, "agent-studio", null, null);
+ }
+
+ private static RangerConstraintResult constraint(long policyId) {
+ return new RangerConstraintResult("requireApproval", null, policyId,
1L, 0, MatchType.SELF);
+ }
+}
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerConstraintResult.java
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerConstraintResult.java
new file mode 100644
index 000000000..26ead3d83
--- /dev/null
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestRangerConstraintResult.java
@@ -0,0 +1,98 @@
+/*
+ * 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.ranger.plugin.policyengine;
+
+import
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher.MatchType;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestRangerConstraintResult {
+ @Test
+ public void nullParametersBecomeAnEmptyMap() {
+ RangerConstraintResult result = result("requireApproval", null, 10L,
3L, 0, MatchType.SELF);
+
+ assertNotNull(result.getParameters());
+ assertTrue(result.getParameters().isEmpty());
+ }
+
+ @Test
+ public void parametersAreCopiedFromTheInputMap() {
+ Map<String, Object> parameters = new HashMap<>();
+
+ parameters.put("approver", "alice");
+
+ RangerConstraintResult result = result("requireApproval", parameters,
10L, 3L, 0, MatchType.SELF);
+
+ parameters.put("approver", "bob");
+ parameters.put("extra", "x");
+
+ assertEquals("alice", result.getParameters().get("approver"));
+ assertFalse(result.getParameters().containsKey("extra"));
+ assertEquals(1, result.getParameters().size());
+ }
+
+ @Test
+ public void equalsAndHashCodeIncludePolicyPriority() {
+ RangerConstraintResult result = result("requireApproval",
mapOf("approver", "alice"), 10L, 3L, 0, MatchType.SELF);
+ RangerConstraintResult same = result("requireApproval",
mapOf("approver", "alice"), 10L, 3L, 0, MatchType.SELF);
+ RangerConstraintResult higher = result("requireApproval",
mapOf("approver", "alice"), 10L, 3L, 1, MatchType.SELF);
+
+ assertEquals(result, same);
+ assertEquals(result.hashCode(), same.hashCode());
+ assertNotEquals(result, higher);
+ assertTrue(result.toString().contains("policyPriority=0"));
+ assertTrue(result.toString().contains("requireApproval"));
+ }
+
+ @Test
+ public void comparatorOrdersByNamePriorityMatchTypeAndPolicyId() {
+ RangerConstraintResult maxRows = result("maxRows", null, 20L,
1L, 1, MatchType.DESCENDANT);
+ RangerConstraintResult lowPriority = result("requireApproval",
null, 30L, 1L, 0, MatchType.DESCENDANT);
+ RangerConstraintResult selfMatch = result("requireApproval",
null, 40L, 1L, 1, MatchType.SELF);
+ RangerConstraintResult laterPolicy = result("requireApproval",
null, 12L, 1L, 1, MatchType.DESCENDANT);
+ RangerConstraintResult earlierPolicy = result("requireApproval",
null, 11L, 1L, 1, MatchType.DESCENDANT);
+ List<RangerConstraintResult> constraints = Arrays.asList(laterPolicy,
selfMatch, maxRows, lowPriority, earlierPolicy);
+
+ constraints.sort(RangerConstraintResult.CONSTRAINT_RESULT_COMPARATOR);
+
+ assertEquals(Arrays.asList(maxRows, selfMatch, earlierPolicy,
laterPolicy, lowPriority), constraints);
+ }
+
+ private static RangerConstraintResult result(String name, Map<String,
Object> parameters, long policyId, Long policyVersion, int policyPriority,
MatchType matchType) {
+ return new RangerConstraintResult(name, parameters, policyId,
policyVersion, policyPriority, matchType);
+ }
+
+ private static Map<String, Object> mapOf(String key, String value) {
+ Map<String, Object> ret = new HashMap<>();
+
+ ret.put(key, value);
+
+ return ret;
+ }
+}