Add Match Any Certification to Policies (#19271)

This commit is contained in:
IceS2 2025-01-08 11:16:56 +01:00 committed by GitHub
parent 1f766791fd
commit 9697ee6271
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 0 deletions

View File

@ -200,6 +200,10 @@ public class RBACConditionEvaluator {
String methodName = methodRef.getName();
switch (methodName) {
case "matchAnyCertification" -> {
List<String> certificationLabels = extractMethodArguments(methodRef);
matchAnyCertification(certificationLabels, collector);
}
case "matchAnyTag" -> {
List<String> tags = extractMethodArguments(methodRef);
matchAnyTag(tags, collector);
@ -259,6 +263,22 @@ public class RBACConditionEvaluator {
}
}
public void matchAnyCertification(
List<String> certificationLabels, ConditionCollector collector) {
List<OMQueryBuilder> certificationQueries = new ArrayList<>();
for (String certificationLabel : certificationLabels) {
certificationQueries.add(
queryBuilderFactory.termQuery("certification.tagLabel.tagFQN", certificationLabel));
}
OMQueryBuilder certificationQueriesCombined;
if (certificationQueries.size() == 1) {
certificationQueriesCombined = certificationQueries.get(0);
} else {
certificationQueriesCombined = queryBuilderFactory.boolQuery().should(certificationQueries);
}
collector.addMust(certificationQueriesCombined);
}
public void isOwner(User user, ConditionCollector collector) {
List<OMQueryBuilder> ownerQueries = new ArrayList<>();
ownerQueries.add(queryBuilderFactory.termQuery("owners.id", user.getId().toString()));

View File

@ -5,8 +5,10 @@ import static org.openmetadata.schema.type.Include.NON_DELETED;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.Function;
import org.openmetadata.schema.type.AssetCertification;
import org.openmetadata.schema.type.TagLabel;
import org.openmetadata.service.Entity;
import org.openmetadata.service.security.policyevaluator.SubjectContext.PolicyContext;
@ -158,6 +160,43 @@ public class RuleEvaluator {
return false;
}
@Function(
name = "matchAnyCertification",
input = "List of comma separated Certification fully qualified names",
description =
"Returns true if the entity being accessed has any of the Certification given as input",
examples = {"matchAnyCertification('Certification.Silver', 'Certification.Gold')"})
@SuppressWarnings("unused") // Used in SpelExpressions
public boolean matchAnyCertification(String... tagFQNs) {
if (expressionValidation) {
for (String tagFqn : tagFQNs) {
Entity.getEntityReferenceByName(Entity.TAG, tagFqn, NON_DELETED); // Validate tag exists
}
return false;
}
if (resourceContext == null) {
return false;
}
Optional<AssetCertification> oCertification =
Optional.ofNullable(resourceContext.getEntity().getCertification());
if (oCertification.isEmpty()) {
LOG.debug(
"matchAnyCertification {} resourceCertification is null.", Arrays.toString(tagFQNs));
return false;
} else {
AssetCertification certification = oCertification.get();
LOG.debug(
"matchAnyCertification {} resourceCertification {}",
Arrays.toString(tagFQNs),
certification.getTagLabel().getTagFQN());
return Arrays.stream(tagFQNs)
.anyMatch(tagFQN -> tagFQN.equals(certification.getTagLabel().getTagFQN()));
}
}
@Function(
name = "matchTeam",
input = "None",

View File

@ -25,6 +25,7 @@ import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.schema.entity.teams.Role;
import org.openmetadata.schema.entity.teams.Team;
import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.type.AssetCertification;
import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.TagLabel;
@ -187,6 +188,36 @@ class RuleEvaluatorTest {
assertTrue(evaluateExpression("!matchAnyTag('tag4')"));
}
@Test
void test_matchAnyCertification() {
// Certification is not Present
assertFalse(evaluateExpression("!matchAnyCertification('Certification.Gold')"));
assertFalse(
evaluateExpression("!matchAnyCertification('Certification.Gold', 'Certification.Silver')"));
assertFalse(evaluateExpression("matchAnyCertification('Certification.Bronze')"));
table.withCertification(
new AssetCertification().withTagLabel(new TagLabel().withTagFQN("Certification.Gold")));
// Certification is present
assertTrue(
evaluateExpression("matchAnyCertification('Certification.Gold', 'Certification.Silver')"));
assertFalse(
evaluateExpression("!matchAnyCertification('Certification.Gold', 'Certification.Silver')"));
assertTrue(evaluateExpression("matchAnyCertification('Certification.Gold')"));
assertFalse(evaluateExpression("!matchAnyCertification('Certification.Gold')"));
// Certification is different
assertFalse(
evaluateExpression(
"matchAnyCertification('Certification.Bronze', 'Certification.Silver')"));
assertTrue(
evaluateExpression(
"!matchAnyCertification('Certification.Bronze', 'Certification.Silver')"));
assertFalse(evaluateExpression("matchAnyCertification('Certification.Bronze')"));
assertTrue(evaluateExpression("!matchAnyCertification('Certification.Bronze')"));
}
@Test
void test_matchTeam() {
// Create a team hierarchy