Throw error if multiple rules within policy have same operation (#2344)

This commit is contained in:
Matt 2022-01-22 01:09:51 -08:00 committed by GitHub
parent 10e71a7e09
commit 319fde9207
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 26 deletions

View File

@ -19,7 +19,9 @@ import java.io.IOException;
import java.net.URI;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -34,6 +36,7 @@ import org.openmetadata.catalog.security.policyevaluator.PolicyEvaluator;
import org.openmetadata.catalog.type.ChangeDescription;
import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.Include;
import org.openmetadata.catalog.type.MetadataOperation;
import org.openmetadata.catalog.type.PolicyType;
import org.openmetadata.catalog.util.EntityInterface;
import org.openmetadata.catalog.util.EntityUtil;
@ -191,18 +194,32 @@ public class PolicyRepository extends EntityRepository<Policy> {
return;
}
LOG.debug("Validating rules for {} policy: {}", PolicyType.AccessControl, policy.getName());
Set<MetadataOperation> operations = new HashSet<>();
for (Object ruleObject : policy.getRules()) {
// Cast to access control policy Rule.
Rule rule = JsonUtils.readValue(JsonUtils.getJsonStructure(ruleObject).toString(), Rule.class);
// If the operation is not specified or if all user (subject) and entity (object) attributes are null, the rule
// is invalid.
if (rule.getOperation() == null
|| (rule.getEntityTagAttr() == null && rule.getEntityTypeAttr() == null && rule.getUserRoleAttr() == null)) {
if (rule.getOperation() == null) {
throw new IllegalArgumentException(
String.format(
"Found invalid rule %s within policy %s. Check if operation is non-null "
+ "and at least one among the user (subject) and entity (object) attributes is specified",
rule, policy.getName()));
"Found invalid rule %s within policy %s. Please ensure operation is non-null",
rule.getName(), policy.getName()));
}
if (!operations.add(rule.getOperation())) {
throw new IllegalArgumentException(
String.format(
"Found multiple rules with operation %s within policy %s. Please ensure that operation across all rules within the policy are distinct",
rule.getOperation(), policy.getName()));
}
// If all user (subject) and entity (object) attributes are null, the rule is invalid.
if (rule.getEntityTagAttr() == null && rule.getEntityTypeAttr() == null && rule.getUserRoleAttr() == null) {
throw new IllegalArgumentException(
String.format(
"Found invalid rule %s within policy %s. Please ensure that at least one among the user (subject) and entity (object) attributes is specified",
rule.getName(), policy.getName()));
}
}
// No validation errors, if execution reaches here.

View File

@ -160,20 +160,52 @@ public class PolicyResourceTest extends EntityResourceTest<Policy> {
@Test
void post_AccessControlPolicyWithValidRules_200_ok(TestInfo test) throws IOException {
CreatePolicy create = createAccessControlPolicyWithValidRules(test);
List<Rule> rules = new ArrayList<>();
rules.add(
PolicyUtils.accessControlRule(null, null, "DataConsumer", MetadataOperation.UpdateDescription, true, 0, true));
rules.add(PolicyUtils.accessControlRule(null, null, "DataConsumer", MetadataOperation.UpdateTags, true, 1, true));
CreatePolicy create = createAccessControlPolicyWithRules(getEntityName(test), rules);
createAndCheckEntity(create, adminAuthHeaders());
}
@Test
void post_AccessControlPolicyWithInvalidRules_400_error(TestInfo test) throws IOException {
CreatePolicy create = createAccessControlPolicyWithInvalidRules(test);
void post_AccessControlPolicyWithInvalidRules_400_error(TestInfo test) {
List<Rule> rules = new ArrayList<>();
rules.add(
PolicyUtils.accessControlRule("rule21", null, null, null, MetadataOperation.UpdateDescription, true, 0, true));
CreatePolicy create = createAccessControlPolicyWithRules(getEntityName(test), rules);
HttpResponseException exception =
assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
assertResponseContains(
exception,
BAD_REQUEST,
"Check if operation is non-null and at least one among the user (subject) "
+ "and entity (object) attributes is specified");
String.format(
"Found invalid rule rule21 within policy %s. Please ensure that at least one among the user "
+ "(subject) and entity (object) attributes is specified",
getEntityName(test)));
}
@Test
void post_AccessControlPolicyWithDuplicateRules_400_error(TestInfo test) {
List<Rule> rules = new ArrayList<>();
rules.add(
PolicyUtils.accessControlRule(
"rule1", null, null, "DataConsumer", MetadataOperation.UpdateDescription, true, 0, true));
rules.add(
PolicyUtils.accessControlRule(
"rule2", null, null, "DataConsumer", MetadataOperation.UpdateTags, true, 1, true));
rules.add(
PolicyUtils.accessControlRule(
"rule3", null, null, "DataConsumer", MetadataOperation.UpdateTags, true, 1, true));
CreatePolicy create = createAccessControlPolicyWithRules(getEntityName(test), rules);
HttpResponseException exception =
assertThrows(HttpResponseException.class, () -> createEntity(create, adminAuthHeaders()));
assertResponseContains(
exception,
BAD_REQUEST,
String.format(
"Found multiple rules with operation UpdateTags within policy %s. Please ensure that operation across all rules within the policy are distinct",
getEntityName(test)));
}
@Test
@ -416,20 +448,6 @@ public class PolicyResourceTest extends EntityResourceTest<Policy> {
.withOwner(USER_OWNER1);
}
private CreatePolicy createAccessControlPolicyWithInvalidRules(TestInfo test) {
List<Rule> rules = new ArrayList<>();
rules.add(PolicyUtils.accessControlRule(null, null, null, MetadataOperation.UpdateDescription, true, 0, true));
return createAccessControlPolicyWithRules(getEntityName(test), rules);
}
private CreatePolicy createAccessControlPolicyWithValidRules(TestInfo test) {
List<Rule> rules = new ArrayList<>();
rules.add(
PolicyUtils.accessControlRule(null, null, "DataConsumer", MetadataOperation.UpdateDescription, true, 0, true));
rules.add(PolicyUtils.accessControlRule(null, null, "DataConsumer", MetadataOperation.UpdateTags, true, 1, true));
return createAccessControlPolicyWithRules(getEntityName(test), rules);
}
private static Location createLocation() throws HttpResponseException {
CreateLocation createLocation = LocationResourceTest.create(LOCATION_NAME, AWS_STORAGE_SERVICE_REFERENCE);
return TestUtils.post(getResource("locations"), createLocation, Location.class, adminAuthHeaders());