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 787ad4b85 RANGER-5851: Admin: persist constraintDefs of service
definitions (#1327)
787ad4b85 is described below
commit 787ad4b85b4ec9c1b66be355af98819a5e9d71fc
Author: Vyom Mani Tiwari <[email protected]>
AuthorDate: Sun Oct 25 12:42:04 2026 +0530
RANGER-5851: Admin: persist constraintDefs of service definitions (#1327)
* RANGER-5851: Admin: persist constraintDefs of service definitions
* RANGER-5851: Admin: persist constraintDefs of service definitions
* RANGER-5851: Admin: persist constraintDefs of service definitions
* RANGER-5851: incorporated review comments
---
.../ranger/plugin/errors/ValidationErrorCode.java | 7 +
.../validation/RangerServiceDefValidator.java | 270 ++++++++++++++++++++-
.../ranger/plugin/model/TestRangerServiceDef.java | 8 +-
.../validation/TestRangerServiceDefValidator.java | 166 +++++++++++++
dev-support/checkstyle-suppressions.xml | 1 +
.../optimized/current/ranger_core_db_mysql.sql | 3 +
.../patches/079-add-def_text-to-x_service_def.sql | 30 +++
.../optimized/current/ranger_core_db_oracle.sql | 3 +
.../patches/079-add-def_text-to-x_service_def.sql | 24 ++
.../optimized/current/ranger_core_db_postgres.sql | 3 +
.../patches/079-add-def_text-to-x_service_def.sql | 32 +++
.../current/ranger_core_db_sqlanywhere.sql | 3 +
.../patches/079-add-def_text-to-x_service_def.sql | 20 ++
.../optimized/current/ranger_core_db_sqlserver.sql | 3 +
.../patches/079-add-def_text-to-x_service_def.sql | 22 ++
.../java/org/apache/ranger/biz/ServiceDBStore.java | 18 ++
.../org/apache/ranger/entity/XXServiceDefBase.java | 27 +++
.../patch/PatchForServiceDefJson_J10067.java | 134 ++++++++++
.../service/RangerServiceDefServiceBase.java | 73 +++++-
.../org/apache/ranger/biz/TestServiceDBStore.java | 38 ++-
.../patch/TestPatchForServiceDefJson_J10067.java | 113 +++++++++
.../service/TestRangerServiceDefService.java | 201 +++++++++++++++
.../service/TestRangerServiceDefServiceBase.java | 93 +++++++
23 files changed, 1273 insertions(+), 19 deletions(-)
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 83cae22d8..976dc7944 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
@@ -67,6 +67,13 @@ public enum ValidationErrorCode {
SERVICE_DEF_VALIDATION_ERR_INVALID_SERVICE_RESOURCE_LEVELS(2021,
"Resource-def levels are not in increasing order in an hierarchy"),
SERVICE_DEF_VALIDATION_ERR_NOT_LOWERCASE_NAME(2022, "{0}:[{1}] Invalid
resource name. Resource name should consist of only lowercase, hyphen or
underscore characters"),
SERVICE_DEF_VALIDATION_ERR_INVALID_MANADORY_VALUE_FOR_SERVICE_RESOURCE(2023,
"{0} cannot be mandatory because {1}(parent) is not mandatory"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_RESOURCE(2026,
"resource[{0}] of constraint def[{1}] is not defined on the service def"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_MISSING_ANCESTOR(2027, "constraint
def[{0}] lists resource[{1}] without ancestor[{2}]"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_ACCESS_TYPE(2028, "access
type[{0}] of constraint def[{1}] is not defined on the service def"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_MISSING_TYPE(2029, "type of
constraint def[{0}] parameter[{1}] was null/empty"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_INVALID_TYPE(2030, "type[{0}]
of constraint def[{1}] parameter[{2}] is not among valid types: {3}"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_UNKNOWN_ENUM(2031,
"subtype[{0}] of constraint def[{1}] parameter[{2}] was not among defined
enums[{3}]"),
+ SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_SUBTYPE_NOT_EMPTY(2032,
"subtype[{0}] of constraint def[{1}] parameter[{2}] must be empty when type is
[{3}]"),
// POLICY VALIDATION
POLICY_VALIDATION_ERR_UNSUPPORTED_ACTION(3001, "Internal error: method
signature isValid(Long) is only supported for DELETE"),
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefValidator.java
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefValidator.java
index 1f0c99d29..45725b476 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefValidator.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefValidator.java
@@ -27,6 +27,8 @@
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
+import
org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintParamDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskTypeDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
@@ -50,7 +52,8 @@
public class RangerServiceDefValidator extends RangerValidator {
private static final Logger LOG =
LoggerFactory.getLogger(RangerServiceDefValidator.class);
- private static final Set<String> VALID_CONFIG_TYPES =
ImmutableSet.of("bool", "enum", "int", "string", "password", "path");
+ private static final Set<String> VALID_CONFIG_TYPES =
ImmutableSet.of("bool", "enum", "int", "string", "password", "path");
+ private static final Set<String> VALID_CONSTRAINT_PARAM_TYPES =
ImmutableSet.of("string", "int", "bool", "enum");
public RangerServiceDefValidator(ServiceStore store) {
super(store);
@@ -220,6 +223,7 @@ boolean isValid(final RangerServiceDef serviceDef, final
Action action, final Li
}
valid = isValidPolicyConditions(serviceDef.getId(),
serviceDef.getPolicyConditions(), failures, action) && valid;
+ valid = isValidConstraintDefs(serviceDef, failures) && valid;
valid = isValidDataMaskTypes(serviceDef.getId(),
serviceDef.getDataMaskDef().getMaskTypes(), failures, action) && valid;
}
@@ -532,6 +536,270 @@ boolean isValidPolicyConditions(Long serviceDefId,
List<RangerPolicyConditionDef
return valid;
}
+ boolean isValidConstraintDefs(RangerServiceDef serviceDef,
List<ValidationFailureDetails> failures) {
+ LOG.debug("==> RangerServiceDefValidator.isValidConstraintDefs({},
{})", serviceDef, failures);
+
+ boolean valid = true;
+
+ if (serviceDef == null ||
CollectionUtils.isEmpty(serviceDef.getConstraintDefs())) {
+ LOG.debug("constraint def collection was null/empty. Ok.");
+ } else {
+ Map<String, RangerResourceDef> resourceDefs =
resourceDefMap(serviceDef.getResources());
+ Set<String> accessTypes =
accessTypeNames(serviceDef.getAccessTypes());
+ Map<String, RangerEnumDef> enumDefs =
getEnumDefMap(serviceDef.getEnums());
+ Set<Long> ids = new HashSet<>();
+ Set<String> names = new HashSet<>();
+
+ for (RangerConstraintDef constraintDef :
serviceDef.getConstraintDefs()) {
+ if (constraintDef == null) {
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def")
+ .isMissing()
+ .becauseOf("constraint def was null")
+ .build());
+
+ valid = false;
+
+ continue;
+ }
+
+ String constraintName = constraintDef.getName();
+
+ valid = isUnique(constraintDef.getItemId(), ids, "constraint
def itemId", "constraint defs", failures) && valid;
+ valid = isUnique(constraintName, names, "constraint def name",
"constraint defs", failures) && valid;
+ valid = isValidConstraintResources(constraintDef,
resourceDefs, failures) && valid;
+ valid = isValidConstraintAccessTypes(constraintDef,
accessTypes, failures) && valid;
+ valid = isValidConstraintParams(constraintDef, enumDefs,
failures) && valid;
+ }
+ }
+
+ LOG.debug("<== RangerServiceDefValidator.isValidConstraintDefs({},
{}): {}", serviceDef, failures, valid);
+
+ return valid;
+ }
+
+ private boolean isValidConstraintResources(RangerConstraintDef
constraintDef, Map<String, RangerResourceDef> resourceDefs,
List<ValidationFailureDetails> failures) {
+ boolean valid = true;
+ List<String> resources = constraintDef.getResources();
+ String constraintName = constraintDef.getName();
+
+ if (CollectionUtils.isEmpty(resources)) {
+ return true;
+ }
+
+ Set<String> listed = new HashSet<>();
+
+ for (String resourceName : resources) {
+ if (StringUtils.isNotBlank(resourceName)) {
+ listed.add(resourceName);
+ }
+ }
+
+ for (String resourceName : resources) {
+ if (StringUtils.isBlank(resourceName) ||
!resourceDefs.containsKey(resourceName)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_RESOURCE;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def resource")
+ .subField(StringUtils.isBlank(resourceName) ?
constraintName : resourceName)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(resourceName,
constraintName))
+ .build());
+
+ valid = false;
+
+ continue;
+ }
+
+ if (!hasConstraintAncestors(resourceName, listed, resourceDefs,
constraintName, failures)) {
+ valid = false;
+ }
+ }
+
+ return valid;
+ }
+
+ private boolean hasConstraintAncestors(String resourceName, Set<String>
listed, Map<String, RangerResourceDef> resourceDefs, String constraintName,
List<ValidationFailureDetails> failures) {
+ Set<String> seen = new HashSet<>();
+ RangerResourceDef resourceDef = resourceDefs.get(resourceName);
+ String parent = resourceDef == null ? null :
resourceDef.getParent();
+
+ seen.add(resourceName);
+
+ while (StringUtils.isNotBlank(parent)) {
+ if (!seen.add(parent)) {
+ break;
+ }
+
+ if (!listed.contains(parent)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_MISSING_ANCESTOR;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def ancestor")
+ .subField(resourceName)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(constraintName,
resourceName, parent))
+ .build());
+
+ return false;
+ }
+
+ RangerResourceDef parentDef = resourceDefs.get(parent);
+
+ parent = parentDef == null ? null : parentDef.getParent();
+ }
+
+ return true;
+ }
+
+ private boolean isValidConstraintAccessTypes(RangerConstraintDef
constraintDef, Set<String> accessTypes, List<ValidationFailureDetails>
failures) {
+ boolean valid = true;
+ List<String> constraintAccessTypes = constraintDef.getAccessTypes();
+
+ if (CollectionUtils.isEmpty(constraintAccessTypes)) {
+ return true;
+ }
+
+ String constraintName = constraintDef.getName();
+
+ for (String accessType : constraintAccessTypes) {
+ if (StringUtils.isBlank(accessType) ||
!accessTypes.contains(accessType)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_ACCESS_TYPE;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def access type")
+ .subField(StringUtils.isBlank(accessType) ?
constraintName : accessType)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(accessType,
constraintName))
+ .build());
+
+ valid = false;
+ }
+ }
+
+ return valid;
+ }
+
+ private boolean isValidConstraintParams(RangerConstraintDef constraintDef,
Map<String, RangerEnumDef> enumDefs, List<ValidationFailureDetails> failures) {
+ boolean valid = true;
+ List<RangerConstraintParamDef> parameters =
constraintDef.getParameters();
+ String constraintName =
constraintDef.getName();
+
+ if (CollectionUtils.isEmpty(parameters)) {
+ return true;
+ }
+
+ Set<String> paramNames = new HashSet<>();
+
+ for (RangerConstraintParamDef parameter : parameters) {
+ if (parameter == null) {
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def parameter")
+ .subField(constraintName)
+ .isMissing()
+ .becauseOf("constraint def parameter was null")
+ .build());
+
+ valid = false;
+
+ continue;
+ }
+
+ String paramName = parameter.getName();
+
+ valid = isUnique(paramName, constraintName, paramNames,
"constraint def parameter name", "constraint def parameters", failures) &&
valid;
+
+ String type = parameter.getType();
+
+ if (StringUtils.isBlank(type)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_MISSING_TYPE;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def parameter type")
+ .subField(paramName)
+ .isMissing()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(constraintName, paramName))
+ .build());
+
+ valid = false;
+ } else if (!VALID_CONSTRAINT_PARAM_TYPES.contains(type)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_INVALID_TYPE;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def parameter type")
+ .subField(paramName)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(type, constraintName,
paramName, VALID_CONSTRAINT_PARAM_TYPES))
+ .build());
+
+ valid = false;
+ } else if ("enum".equals(type)) {
+ String subType = parameter.getSubType();
+
+ if (StringUtils.isBlank(subType) ||
!enumDefs.containsKey(subType)) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_UNKNOWN_ENUM;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def parameter subtype")
+ .subField(paramName)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(subType,
constraintName, paramName, enumDefs.keySet()))
+ .build());
+
+ valid = false;
+ }
+ } else if (StringUtils.isNotBlank(parameter.getSubType())) {
+ ValidationErrorCode error =
ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_SUBTYPE_NOT_EMPTY;
+
+ failures.add(new ValidationFailureDetailsBuilder()
+ .field("constraint def parameter subtype")
+ .subField(paramName)
+ .isSemanticallyIncorrect()
+ .errorCode(error.getErrorCode())
+ .becauseOf(error.getMessage(parameter.getSubType(),
constraintName, paramName, type))
+ .build());
+
+ valid = false;
+ }
+ }
+
+ return valid;
+ }
+
+ private Map<String, RangerResourceDef>
resourceDefMap(List<RangerResourceDef> resources) {
+ Map<String, RangerResourceDef> resourceDefs = new HashMap<>();
+
+ if (resources != null) {
+ for (RangerResourceDef resourceDef : resources) {
+ if (resourceDef != null &&
StringUtils.isNotBlank(resourceDef.getName())) {
+ resourceDefs.put(resourceDef.getName(), resourceDef);
+ }
+ }
+ }
+
+ return resourceDefs;
+ }
+
+ private Set<String> accessTypeNames(List<RangerAccessTypeDef>
accessTypeDefs) {
+ Set<String> accessTypes = new HashSet<>();
+
+ if (accessTypeDefs != null) {
+ for (RangerAccessTypeDef accessTypeDef : accessTypeDefs) {
+ if (accessTypeDef != null &&
StringUtils.isNotBlank(accessTypeDef.getName())) {
+ accessTypes.add(accessTypeDef.getName());
+ }
+ }
+ }
+
+ return accessTypes;
+ }
+
boolean isValidConfigs(List<RangerServiceConfigDef> configs,
List<RangerEnumDef> enumDefs, List<ValidationFailureDetails> failures) {
LOG.debug("==> RangerServiceDefValidator.isValidConfigs({}, {}, {})",
configs, enumDefs, failures);
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/model/TestRangerServiceDef.java
b/agents-common/src/test/java/org/apache/ranger/plugin/model/TestRangerServiceDef.java
index c36eb6232..1cb4438a8 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/model/TestRangerServiceDef.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/model/TestRangerServiceDef.java
@@ -365,7 +365,7 @@ public void test14_ConstraintDefsJsonRoundTrip() throws
Exception {
param.setName("approver");
param.setLabel("Approver");
param.setDescription("User who must approve");
- param.setType("user");
+ param.setType("string");
param.setSubType(null);
Assertions.assertNull(param.getSubType());
param.setMandatory(null);
@@ -472,7 +472,7 @@ public void test14_ConstraintDefsJsonRoundTrip() throws
Exception {
+ "\"name\":\"approver\","
+ "\"label\":\"Approver\","
+ "\"description\":\"User who must approve\","
- + "\"type\":\"user\","
+ + "\"type\":\"string\","
+ "\"mandatory\":true,"
+ "\"defaultValue\":\"alice\","
+ "\"rbKeyLabel\":\"rb.approver\","
@@ -496,13 +496,13 @@ public void test14_ConstraintDefsJsonRoundTrip() throws
Exception {
Map<String, String> tbl = new HashMap<>();
String canonicalResource = StringUtil.dedupString(new String("tool"),
tbl);
String canonicalName = StringUtil.dedupString(new
String("requireApproval"), tbl);
- String canonicalType = StringUtil.dedupString(new String("user"),
tbl);
+ String canonicalType = StringUtil.dedupString(new String("string"),
tbl);
String canonicalSubType = StringUtil.dedupString(new
String("MaskTypes"), tbl);
parsedDef.setName(new String("requireApproval"));
List<String> resources = new ArrayList<>();
resources.add(new String("tool"));
parsedDef.setResources(resources);
- parsedDef.getParameters().get(0).setType(new String("user"));
+ parsedDef.getParameters().get(0).setType(new String("string"));
parsedDef.getParameters().get(0).setSubType(new String("MaskTypes"));
parsedDef.dedupStrings(tbl);
Assertions.assertSame(canonicalName, parsedDef.getName());
diff --git
a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerServiceDefValidator.java
b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerServiceDefValidator.java
index a178f3174..d832e01ed 100644
---
a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerServiceDefValidator.java
+++
b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerServiceDefValidator.java
@@ -19,8 +19,11 @@
package org.apache.ranger.plugin.model.validation;
+import org.apache.ranger.plugin.errors.ValidationErrorCode;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
+import
org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintParamDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
@@ -32,11 +35,14 @@
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -662,4 +668,164 @@ public final void test_isValidConfigs_enumTypeBranches() {
assertFalse(validator.isValidConfigs(configs, enumDefs, failures));
utils.checkFailureForSemanticError(failures, "config def subtype",
"enumCfg");
}
+
+ @Test
+ public final void test_isValidConstraintDefs() {
+ assertTrue(validator.isValidConstraintDefs(new RangerServiceDef(),
failures));
+ assertTrue(failures.isEmpty());
+
+ RangerServiceDef def = constraintServiceDef();
+ RangerConstraintDef valid = constraintDef(1L, "requireApproval",
Arrays.asList("database", "udf"), Arrays.asList("execute"));
+ List<RangerConstraintParamDef> validParams = new ArrayList<>();
+ validParams.add(param("approver", "string", null, true));
+ validParams.add(param("rowCount", "int", null, false));
+ validParams.add(param("enabled", "bool", null, false));
+ validParams.add(param("mode", "enum", "authType", false));
+ valid.setParameters(validParams);
+ def.setConstraintDefs(Collections.singletonList(valid));
+ assertTrue(validator.isValidConstraintDefs(def, failures));
+ assertTrue(failures.isEmpty());
+
+ RangerConstraintDef emptyResources = constraintDef(1L,
"requireApproval", new ArrayList<>(), Arrays.asList("execute"));
+
emptyResources.setParameters(Collections.singletonList(param("approver",
"string", null, true)));
+ def.setConstraintDefs(Collections.singletonList(emptyResources));
+ assertTrue(validator.isValidConstraintDefs(def, failures));
+ assertTrue(failures.isEmpty());
+
+ assertFalse(validator.isValidConfigType("user", "approver", failures));
+ utils.checkFailureForSemanticError(failures, "config def type",
"approver");
+ failures.clear();
+ assertFalse(validator.isValidConfigType("group", "approverGroup",
failures));
+ utils.checkFailureForSemanticError(failures, "config def type",
"approverGroup");
+ failures.clear();
+ assertFalse(validator.isValidConfigType("role", "approverRole",
failures));
+ utils.checkFailureForSemanticError(failures, "config def type",
"approverRole");
+ }
+
+ @Test
+ public final void test_isValid_rejectsInvalidConstraintDef() {
+ RangerServiceDef def = constraintServiceDef();
+ def.setName("agent");
+ def.setDisplayName("Agent");
+ def.setConstraintDefs(Collections.singletonList(constraintDef(1L,
"requireApproval", Arrays.asList("missing"), Arrays.asList("select"))));
+
+ assertFalse(validator.isValid(def, Action.CREATE, failures));
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_RESOURCE.getErrorCode());
+ }
+
+ @Test
+ public final void test_isValidConstraintDefs_failures() {
+ RangerServiceDef def = constraintServiceDef();
+ List<RangerConstraintDef> constraintDefs = new ArrayList<>();
+ constraintDefs.add(null);
+
+ RangerConstraintDef missingAncestor = constraintDef(1L, "maxRows",
Arrays.asList("udf"), Arrays.asList("select"));
+
missingAncestor.setParameters(Collections.singletonList(param("rowCount",
"int", null, true)));
+ constraintDefs.add(missingAncestor);
+
+ RangerConstraintDef invalid = constraintDef(1L, " ",
Arrays.asList("missing", ""), Arrays.asList("drop", " "));
+ List<RangerConstraintParamDef> params = new ArrayList<>();
+ params.add(param("rowCount", "password", null, true));
+ params.add(param("rowCount", "int", null, false));
+ params.add(null);
+ params.add(param("mode", "enum", "no-such-enum", false));
+ params.add(param("kind", "enum", " ", false));
+ params.add(param("approver", "string", "authType", true));
+ params.add(param("approverUser", "user", null, false));
+ params.add(param("approverGroup", "group", null, false));
+ params.add(param("approverRole", "role", null, false));
+ params.add(param("limit", null, null, false));
+ invalid.setParameters(params);
+ constraintDefs.add(invalid);
+
+ RangerConstraintDef duplicateName = constraintDef(2L, "maxRows",
Arrays.asList("database", "table"), Arrays.asList("select"));
+
duplicateName.setParameters(Collections.singletonList(param("rowCount", "int",
null, true)));
+ constraintDefs.add(duplicateName);
+
+ def.setConstraintDefs(constraintDefs);
+ assertFalse(validator.isValidConstraintDefs(def, failures));
+ utils.checkFailureForMissingValue(failures, "constraint def");
+ utils.checkFailureForMissingValue(failures, "constraint def name");
+ utils.checkFailureForSemanticError(failures, "constraint def itemId",
"1");
+ utils.checkFailureForSemanticError(failures, "constraint def name",
"maxRows");
+ utils.checkFailureForSemanticError(failures, "constraint def
ancestor", "udf");
+ utils.checkFailureForSemanticError(failures, "constraint def
resource", "missing");
+ utils.checkFailureForSemanticError(failures, "constraint def access
type", "drop");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
type", "rowCount");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
type", "approverUser");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
type", "approverGroup");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
type", "approverRole");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
name", "rowCount");
+ utils.checkFailureForMissingValue(failures, "constraint def
parameter");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
subtype", "mode");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
subtype", "kind");
+ utils.checkFailureForSemanticError(failures, "constraint def parameter
subtype", "approver");
+ utils.checkFailureForMissingValue(failures, "constraint def parameter
type", "limit");
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_RESOURCE.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_MISSING_ANCESTOR.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_UNKNOWN_ACCESS_TYPE.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_MISSING_TYPE.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_INVALID_TYPE.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_UNKNOWN_ENUM.getErrorCode());
+
assertHasErrorCode(ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_CONSTRAINT_PARAM_SUBTYPE_NOT_EMPTY.getErrorCode());
+ }
+
+ private void assertHasErrorCode(int errorCode) {
+ for (ValidationFailureDetails failure : failures) {
+ if (failure.errorCode == errorCode) {
+ return;
+ }
+ }
+
+ fail("expected error code " + errorCode + " in " + failures);
+ }
+
+ private RangerServiceDef constraintServiceDef() {
+ RangerServiceDef def = new RangerServiceDef();
+ def.setResources(utils.createResourceDefs(new Object[][] {
+ {"database", Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, null,
null, 10},
+ {"table", Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, null,
"database", 20},
+ {"udf", Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, null,
"database", 20},
+ {"column", Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, null,
"table", 30}
+ }));
+
+ RangerAccessTypeDef select = new RangerAccessTypeDef();
+ select.setName("select");
+ RangerAccessTypeDef execute = new RangerAccessTypeDef();
+ execute.setName("execute");
+ List<RangerAccessTypeDef> accessTypes = new ArrayList<>();
+ accessTypes.add(select);
+ accessTypes.add(execute);
+ def.setAccessTypes(accessTypes);
+
+ RangerEnumDef enumDef = new RangerEnumDef();
+ enumDef.setName("authType");
+ List<RangerEnumDef> enums = new ArrayList<>();
+ enums.add(enumDef);
+ def.setEnums(enums);
+
+ return def;
+ }
+
+ private RangerConstraintDef constraintDef(Long itemId, String name,
List<String> resources, List<String> accessTypes) {
+ RangerConstraintDef constraintDef = new RangerConstraintDef();
+
+ constraintDef.setItemId(itemId);
+ constraintDef.setName(name);
+ constraintDef.setResources(resources);
+ constraintDef.setAccessTypes(accessTypes);
+
+ return constraintDef;
+ }
+
+ private RangerConstraintParamDef param(String name, String type, String
subType, boolean mandatory) {
+ RangerConstraintParamDef paramDef = new RangerConstraintParamDef();
+
+ paramDef.setName(name);
+ paramDef.setType(type);
+ paramDef.setSubType(subType);
+ paramDef.setMandatory(mandatory);
+
+ return paramDef;
+ }
}
diff --git a/dev-support/checkstyle-suppressions.xml
b/dev-support/checkstyle-suppressions.xml
index f20f609e9..b82da722a 100644
--- a/dev-support/checkstyle-suppressions.xml
+++ b/dev-support/checkstyle-suppressions.xml
@@ -93,4 +93,5 @@
<suppress files="PatchForAtlasPolicyUpdateForEntityRead_J10064"
checks="TypeName"/>
<suppress files="PatchForOzoneServiceDefPolicyConditionUpdate_J10066"
checks="TypeName"/>
<suppress files="PatchForOzoneServiceDefAssumeRoleUpdate_J10065"
checks="TypeName"/>
+ <suppress files="PatchForServiceDefJson_J10067" checks="TypeName"/>
</suppressions>
diff --git a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
index 8ecc59f4a..0818c8590 100644
--- a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
+++ b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
@@ -533,6 +533,7 @@ CREATE TABLE `x_service_def` (
`rb_key_description` varchar(1024) DEFAULT NULL,
`is_enabled` tinyint DEFAULT 1,
`def_options` VARCHAR(1024) DEFAULT NULL NULL,
+`def_text` MEDIUMTEXT NULL DEFAULT NULL,
primary key (`id`),
KEY `x_service_def_added_by_id` (`added_by_id`),
KEY `x_service_def_upd_by_id` (`upd_by_id`),
@@ -1975,6 +1976,7 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('076',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('077',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('078',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('079',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('DB_PATCHES',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10001',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
@@ -2029,4 +2031,5 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10064',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10065',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10066',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10067',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('JAVA_PATCHES',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
diff --git
a/security-admin/db/mysql/patches/079-add-def_text-to-x_service_def.sql
b/security-admin/db/mysql/patches/079-add-def_text-to-x_service_def.sql
new file mode 100644
index 000000000..7acdb8905
--- /dev/null
+++ b/security-admin/db/mysql/patches/079-add-def_text-to-x_service_def.sql
@@ -0,0 +1,30 @@
+-- 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.
+
+drop procedure if exists add_def_text_in_x_service_def;
+
+delimiter ;;
+create procedure add_def_text_in_x_service_def() begin
+
+if not exists (select * from information_schema.columns where
table_schema=database() and table_name = 'x_service_def' and
column_name='def_text') then
+ ALTER TABLE x_service_def ADD def_text MEDIUMTEXT NULL DEFAULT NULL;
+end if;
+
+end;;
+
+delimiter ;
+call add_def_text_in_x_service_def();
+
+drop procedure if exists add_def_text_in_x_service_def;
diff --git
a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
index ddca10bb5..ec8dfff61 100644
--- a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
+++ b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
@@ -662,6 +662,7 @@ rb_key_label VARCHAR(1024) DEFAULT NULL NULL,
rb_key_description VARCHAR(1024) DEFAULT NULL NULL,
is_enabled NUMBER(1) DEFAULT '1' NULL,
def_options VARCHAR(1024) DEFAULT NULL NULL,
+def_text CLOB DEFAULT NULL NULL,
PRIMARY KEY (id),
CONSTRAINT x_service_def_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES
x_portal_user (id),
CONSTRAINT x_service_def_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES
x_portal_user (id)
@@ -2164,6 +2165,7 @@ INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,act
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval, '076',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval, '077',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval, '078',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
+INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval, '079',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval, 'DB_PATCHES',sys_extract_utc(systimestamp),'Ranger
1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_user_module_perm
(id,user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed)
VALUES
(X_USER_MODULE_PERM_SEQ.nextval,getXportalUIdByLoginId('admin'),getModulesIdByName('Reports'),sys_extract_utc(systimestamp),sys_extract_utc(systimestamp),getXportalUIdByLoginId('admin'),getXportalUIdByLoginId('admin'),1);
@@ -2253,5 +2255,6 @@ INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,act
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval,'J10064',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval,'J10065',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval,'J10066',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
+INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval,'J10067',sys_extract_utc(systimestamp),'Ranger
3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h
(id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES
(X_DB_VERSION_H_SEQ.nextval,'JAVA_PATCHES',sys_extract_utc(systimestamp),'Ranger
1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
commit;
diff --git
a/security-admin/db/oracle/patches/079-add-def_text-to-x_service_def.sql
b/security-admin/db/oracle/patches/079-add-def_text-to-x_service_def.sql
new file mode 100644
index 000000000..70d084fca
--- /dev/null
+++ b/security-admin/db/oracle/patches/079-add-def_text-to-x_service_def.sql
@@ -0,0 +1,24 @@
+-- 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.
+
+DECLARE
+ v_count number:=0;
+BEGIN
+ select count(*) into v_count from user_tab_cols where
table_name='X_SERVICE_DEF' and column_name='DEF_TEXT';
+ if (v_count = 0) then
+ execute immediate 'ALTER TABLE x_service_def ADD def_text CLOB
DEFAULT NULL NULL';
+ end if;
+ commit;
+END;/
diff --git
a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
index 654d19aa7..019ab5782 100644
--- a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
+++ b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
@@ -549,6 +549,7 @@ rb_key_label VARCHAR(1024) DEFAULT NULL NULL,
rb_key_description VARCHAR(1024) DEFAULT NULL NULL,
is_enabled BOOLEAN DEFAULT '1' NULL,
def_options VARCHAR(1024) DEFAULT NULL NULL,
+def_text TEXT DEFAULT NULL NULL,
PRIMARY KEY(id),
CONSTRAINT x_service_def_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES
x_portal_user(id),
CONSTRAINT x_service_def_FK_upd_by_id FOREIGN KEY(upd_by_id) REFERENCES
x_portal_user(id)
@@ -2078,6 +2079,7 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('076',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('077',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('078',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('079',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('DB_PATCHES',current_timestamp,'Ranger
1.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_user_module_perm
(user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed)
VALUES
@@ -2186,6 +2188,7 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10064',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10065',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10066',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10067',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('JAVA_PATCHES',current_timestamp,'Ranger
1.0.0',current_timestamp,'localhost','Y');
DROP VIEW IF EXISTS vx_principal;
diff --git
a/security-admin/db/postgres/patches/079-add-def_text-to-x_service_def.sql
b/security-admin/db/postgres/patches/079-add-def_text-to-x_service_def.sql
new file mode 100644
index 000000000..30e74e03e
--- /dev/null
+++ b/security-admin/db/postgres/patches/079-add-def_text-to-x_service_def.sql
@@ -0,0 +1,32 @@
+-- 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.
+
+select 'delimiter start';
+CREATE OR REPLACE FUNCTION add_def_text_in_x_service_def()
+RETURNS void AS $$
+DECLARE
+ v_column_exists integer := 0;
+BEGIN
+ select count(*) into v_column_exists from pg_attribute where attrelid
in(select oid from pg_class where relname='x_service_def') and
attname='def_text';
+ IF v_column_exists = 0 THEN
+ ALTER TABLE x_service_def ADD COLUMN def_text TEXT DEFAULT NULL NULL;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+select 'delimiter end';
+
+select add_def_text_in_x_service_def();
+select 'delimiter end';
+commit;
diff --git
a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
index 678fe343b..cac26327a 100644
---
a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
+++
b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
@@ -497,6 +497,7 @@ create table dbo.x_service_def(
rb_key_description varchar(1024) DEFAULT NULL NULL,
is_enabled tinyint DEFAULT 1 NULL,
def_options varchar(1024) DEFAULT NULL NULL,
+ def_text text DEFAULT NULL NULL,
CONSTRAINT x_service_def_PK_id PRIMARY KEY CLUSTERED(id)
)
GO
@@ -2256,6 +2257,7 @@ GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('077',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('078',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('079',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('DB_PATCHES',CURRENT_TIMESTAMP,'Ranger
1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
@@ -2420,6 +2422,7 @@ GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10065',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10066',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10067',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('JAVA_PATCHES',CURRENT_TIMESTAMP,'Ranger
1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
diff --git
a/security-admin/db/sqlanywhere/patches/079-add-def_text-to-x_service_def.sql
b/security-admin/db/sqlanywhere/patches/079-add-def_text-to-x_service_def.sql
new file mode 100644
index 000000000..a50014bb5
--- /dev/null
+++
b/security-admin/db/sqlanywhere/patches/079-add-def_text-to-x_service_def.sql
@@ -0,0 +1,20 @@
+-- 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.
+
+IF NOT EXISTS(select * from SYS.SYSCOLUMNS where tname = 'x_service_def' and
cname = 'def_text') THEN
+ ALTER TABLE dbo.x_service_def ADD def_text text DEFAULT NULL
NULL;
+END IF;
+GO
+exit
diff --git
a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
index 68c864e74..fef115ed7 100644
--- a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
+++ b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
@@ -1497,6 +1497,7 @@ CREATE TABLE [dbo].[x_service_def](
[rb_key_description] [varchar](1024) DEFAULT NULL NULL,
[is_enabled] [tinyint] DEFAULT 1 NULL,
[def_options] [varchar](1024) DEFAULT NULL NULL,
+ [def_text] [nvarchar](max) DEFAULT NULL NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
@@ -4538,6 +4539,7 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('076',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('077',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('078',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('079',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('DB_PATCHES',CURRENT_TIMESTAMP,'Ranger
1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_user_module_perm
(user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed)
VALUES
(dbo.getXportalUIdByLoginId('admin'),dbo.getModulesIdByName('Reports'),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),dbo.getXportalUIdByLoginId('admin'),1);
INSERT INTO x_user_module_perm
(user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed)
VALUES (dbo.getXportalUIdByLoginId('admin'),dbo.getModulesIdByName('Resource
Based
Policies'),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),dbo.getXportalUIdByLoginId('admin'),1);
@@ -4626,5 +4628,6 @@ INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10064',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10065',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10066',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('J10067',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h
(version,inst_at,inst_by,updated_at,updated_by,active) VALUES
('JAVA_PATCHES',CURRENT_TIMESTAMP,'Ranger
1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
diff --git
a/security-admin/db/sqlserver/patches/079-add-def_text-to-x_service_def.sql
b/security-admin/db/sqlserver/patches/079-add-def_text-to-x_service_def.sql
new file mode 100644
index 000000000..51e9063b4
--- /dev/null
+++ b/security-admin/db/sqlserver/patches/079-add-def_text-to-x_service_def.sql
@@ -0,0 +1,22 @@
+-- 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.
+
+GO
+IF NOT EXISTS(select * from INFORMATION_SCHEMA.columns where table_name =
'x_service_def' and column_name = 'def_text')
+BEGIN
+ ALTER TABLE [dbo].[x_service_def] ADD [def_text] [nvarchar](max)
DEFAULT NULL NULL;
+END
+GO
+exit
diff --git
a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
index 0d3f5bc1b..83e32d3ff 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
@@ -115,6 +115,7 @@
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskTypeDef;
@@ -467,6 +468,7 @@ public RangerServiceDef createServiceDef(RangerServiceDef
serviceDef) throws Exc
List<RangerEnumDef> enums =
serviceDef.getEnums();
RangerDataMaskDef dataMaskDef =
serviceDef.getDataMaskDef();
RangerRowFilterDef rowFilterDef =
serviceDef.getRowFilterDef();
+ List<RangerConstraintDef> constraintDefs =
serviceDef.getConstraintDefs();
List<RangerDataMaskTypeDef> dataMaskTypes = dataMaskDef ==
null || dataMaskDef.getMaskTypes() == null ? new ArrayList<>() :
dataMaskDef.getMaskTypes();
List<RangerAccessTypeDef> dataMaskAccessTypes = dataMaskDef ==
null || dataMaskDef.getAccessTypes() == null ? new ArrayList<>() :
dataMaskDef.getAccessTypes();
List<RangerResourceDef> dataMaskResources = dataMaskDef ==
null || dataMaskDef.getResources() == null ? new ArrayList<>() :
dataMaskDef.getResources();
@@ -698,6 +700,8 @@ public RangerServiceDef createServiceDef(RangerServiceDef
serviceDef) throws Exc
}
}
+ updateServiceDefText(createdSvcDef, constraintDefs);
+
RangerServiceDef createdServiceDef =
serviceDefService.getPopulatedViewObject(createdSvcDef);
dataHistService.createObjectDataHistory(createdServiceDef,
RangerDataHistService.ACTION_CREATE);
@@ -739,6 +743,7 @@ public RangerServiceDef updateServiceDef(RangerServiceDef
serviceDef) throws Exc
List<RangerEnumDef> enums =
serviceDef.getEnums() != null ? serviceDef.getEnums() : new ArrayList<>();
RangerDataMaskDef dataMaskDef =
serviceDef.getDataMaskDef();
RangerRowFilterDef rowFilterDef =
serviceDef.getRowFilterDef();
+ List<RangerConstraintDef> constraintDefs =
serviceDef.getConstraintDefs();
RangerServiceDefHelper defHelper = new
RangerServiceDefHelper(serviceDef, false);
defHelper.patchServiceDefWithDefaultValues();
@@ -753,6 +758,8 @@ public RangerServiceDef updateServiceDef(RangerServiceDef
serviceDef) throws Exc
updateChildObjectsOfServiceDef(createdSvcDef, configs, resources,
accessTypes, policyConditions, contextEnrichers, enums, dataMaskDef,
rowFilterDef);
+ updateServiceDefText(createdSvcDef, constraintDefs);
+
RangerServiceDef updatedSvcDef = getServiceDef(serviceDefId);
dataHistService.createObjectDataHistory(updatedSvcDef,
RangerDataHistService.ACTION_UPDATE);
@@ -3248,6 +3255,17 @@ boolean
hasServiceConfigForPluginChanged(List<XXServiceConfigMap> dbConfigMaps,
return ret;
}
+ // Writes x_service_def.def_text after the child rows. constraintDefs are
stored only in this JSON.
+ private void updateServiceDefText(XXServiceDef xServiceDef,
List<RangerConstraintDef> constraintDefs) {
+ if (xServiceDef == null) {
+ return;
+ }
+
+ xServiceDef.setDefText(serviceDefService.buildDefText(xServiceDef,
constraintDefs));
+
+ daoMgr.getXXServiceDef().update(xServiceDef);
+ }
+
private void updateChildObjectsOfServiceDef(XXServiceDef createdSvcDef,
List<RangerServiceConfigDef> configs,
List<RangerResourceDef> resources, List<RangerAccessTypeDef>
accessTypes,
List<RangerPolicyConditionDef> policyConditions,
List<RangerContextEnricherDef> contextEnrichers,
diff --git
a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceDefBase.java
b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceDefBase.java
index ba86de242..567d5ace0 100644
---
a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceDefBase.java
+++
b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceDefBase.java
@@ -93,6 +93,14 @@ public abstract class XXServiceDefBase extends XXDBBase
implements Serializable
@Column(name = "def_options")
protected String defOptions;
+ /**
+ * defText of the XXServiceDef
+ * <ul>
+ * </ul>
+ */
+ @Column(name = "def_text")
+ protected String defText;
+
/**
* rbKeyLabel of the XXServiceDef
* <ul>
@@ -238,6 +246,24 @@ public void setDefOptions(String options) {
this.defOptions = options;
}
+ /**
+ * Returns the value for the member attribute <b>defText</b>
+ *
+ * @return String - value of member attribute <b>defText</b> .
+ */
+ public String getDefText() {
+ return this.defText;
+ }
+
+ /**
+ * This method sets the value to the member attribute <b> defText</b> .
+ *
+ * @param defText Value to set member attribute <b> defText</b>
+ */
+ public void setDefText(String defText) {
+ this.defText = defText;
+ }
+
/**
* Returns the value for the member attribute <b>rbKeyLabel</b>
*
@@ -332,6 +358,7 @@ public boolean equals(Object obj) {
XXServiceDefBase other = (XXServiceDefBase) obj;
return Objects.equals(description, other.description) &&
+ Objects.equals(defText, other.defText) &&
Objects.equals(guid, other.guid) &&
Objects.equals(implClassName, other.implClassName) &&
Objects.equals(label, other.label) &&
diff --git
a/security-admin/src/main/java/org/apache/ranger/patch/PatchForServiceDefJson_J10067.java
b/security-admin/src/main/java/org/apache/ranger/patch/PatchForServiceDefJson_J10067.java
new file mode 100644
index 000000000..d95a5a0a1
--- /dev/null
+++
b/security-admin/src/main/java/org/apache/ranger/patch/PatchForServiceDefJson_J10067.java
@@ -0,0 +1,134 @@
+/*
+ * 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.patch;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.service.RangerServiceDefService;
+import org.apache.ranger.util.CLIUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.List;
+
+@Component
+public class PatchForServiceDefJson_J10067 extends BaseLoader {
+ private static final Logger logger =
LoggerFactory.getLogger(PatchForServiceDefJson_J10067.class);
+
+ @Autowired
+ RangerDaoManager daoMgr;
+
+ @Autowired
+ RangerServiceDefService serviceDefService;
+
+ @Autowired
+ @Qualifier(value = "transactionManager")
+ PlatformTransactionManager txManager;
+
+ public static void main(String[] args) {
+ logger.info("main()");
+ try {
+ PatchForServiceDefJson_J10067 loader =
(PatchForServiceDefJson_J10067)
CLIUtil.getBean(PatchForServiceDefJson_J10067.class);
+
+ loader.init();
+
+ while (loader.isMoreToProcess()) {
+ loader.load();
+ }
+
+ logger.info("Load complete. Exiting!!!");
+ System.exit(0);
+ } catch (Exception e) {
+ logger.error("Error loading", e);
+ System.exit(1);
+ }
+ }
+
+ @Override
+ public void init() throws Exception {
+ // Do Nothing
+ }
+
+ @Override
+ public void printStats() {
+ logger.info("PatchForServiceDefJson_J10067");
+ }
+
+ @Override
+ public void execLoad() {
+ logger.info("==> PatchForServiceDefJson_J10067.execLoad()");
+
+ try {
+ updateServiceDefText();
+ } catch (Exception e) {
+ logger.error("Error while applying PatchForServiceDefJson_J10067",
e);
+ throw new RuntimeException("PatchForServiceDefJson_J10067 failed",
e);
+ }
+
+ logger.info("<== PatchForServiceDefJson_J10067.execLoad()");
+ }
+
+ private void updateServiceDefText() {
+ List<XXServiceDef> serviceDefs = daoMgr.getXXServiceDef().getAll();
+
+ if (CollectionUtils.isEmpty(serviceDefs)) {
+ logger.info("No service-defs found");
+
+ return;
+ }
+
+ TransactionTemplate txTemplate = new TransactionTemplate(txManager);
+
+
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+
+ for (XXServiceDef xServiceDef : serviceDefs) {
+ Long serviceDefId = xServiceDef.getId();
+
+ txTemplate.execute(status -> {
+ XXServiceDef dbServiceDef =
daoMgr.getXXServiceDef().getById(serviceDefId);
+
+ if (dbServiceDef != null &&
StringUtils.isEmpty(dbServiceDef.getDefText())) {
+ // constraintDefs were not stored before def_text existed,
so there are none to carry over
+ String defText =
serviceDefService.buildDefText(dbServiceDef, null);
+
+ if (StringUtils.isEmpty(defText)) {
+ throw new IllegalStateException("failed to build JSON
for service-def(id=" + serviceDefId + ", name=" + dbServiceDef.getName() + ")");
+ }
+
+ dbServiceDef.setDefText(defText);
+
+ daoMgr.getXXServiceDef().update(dbServiceDef);
+
+ logger.info("Stored JSON for service-def(id={}, name={})",
serviceDefId, dbServiceDef.getName());
+ } else if (dbServiceDef != null) {
+ logger.info("JSON already present for service-def(id={},
name={}); skipping", serviceDefId, dbServiceDef.getName());
+ }
+
+ return null;
+ });
+ }
+ }
+}
diff --git
a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceDefServiceBase.java
b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceDefServiceBase.java
index 1b93b2c84..3edaf6778 100644
---
a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceDefServiceBase.java
+++
b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceDefServiceBase.java
@@ -19,6 +19,7 @@
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.ranger.authorization.utils.JsonUtils;
import org.apache.ranger.common.AppConstants;
import org.apache.ranger.common.GUIDUtil;
import org.apache.ranger.common.JSONUtil;
@@ -41,6 +42,7 @@
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef.AccessTypeCategory;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskTypeDef;
@@ -557,6 +559,39 @@ protected T mapViewToEntityBean(V vObj, T xObj, int
operationContext) {
@Override
protected V mapEntityToViewBean(V vObj, T xObj) {
+ return mapServiceDefColumns(vObj, xObj);
+ }
+
+ @Override
+ protected V populateViewBean(T xServiceDef) {
+ V serviceDef = super.populateViewBean(xServiceDef);
+
+ if (!applyDefText(serviceDef, xServiceDef.getDefText())) {
+ loadChildTables(serviceDef, xServiceDef);
+ }
+
+
serviceDef.setMarkerAccessTypes(ServiceDefUtil.getMarkerAccessTypes(serviceDef.getAccessTypes()));
+ addImplicitConditionExpressionIfNeeded(serviceDef);
+ ServiceDefUtil.normalize(serviceDef);
+
+ return serviceDef;
+ }
+
+ // JSON for x_service_def.def_text, built after the child rows are written.
+ // Marker access types, the implicit condition, and read-time options are
left out.
+ public String buildDefText(T xServiceDef, List<RangerConstraintDef>
constraintDefs) {
+ V serviceDef = createViewObject();
+
+ serviceDef.setId(xServiceDef.getId());
+ mapServiceDefColumns(serviceDef, xServiceDef);
+ loadChildTables(serviceDef, xServiceDef);
+ serviceDef.setConstraintDefs(constraintDefs);
+ serviceDef.setMarkerAccessTypes(null);
+
+ return JsonUtils.objectToJson(serviceDef);
+ }
+
+ private V mapServiceDefColumns(V vObj, T xObj) {
vObj.setGuid(xObj.getGuid());
vObj.setVersion(xObj.getVersion());
vObj.setName(xObj.getName());
@@ -572,9 +607,33 @@ protected V mapEntityToViewBean(V vObj, T xObj) {
return vObj;
}
- @Override
- protected V populateViewBean(T xServiceDef) {
- V serviceDef =
super.populateViewBean(xServiceDef);
+ private boolean applyDefText(V serviceDef, String defText) {
+ if (StringUtils.isEmpty(defText)) {
+ return false;
+ }
+
+ V fromJson = JsonUtils.jsonToObject(defText, tViewClass);
+
+ if (fromJson == null) {
+ LOG.warn("failed to read def_text of service-def(id={}, name={});
loading it from child tables", serviceDef.getId(), serviceDef.getName());
+
+ return false;
+ }
+
+ serviceDef.setConfigs(fromJson.getConfigs());
+ serviceDef.setResources(fromJson.getResources());
+ serviceDef.setAccessTypes(fromJson.getAccessTypes());
+ serviceDef.setPolicyConditions(fromJson.getPolicyConditions());
+ serviceDef.setConstraintDefs(fromJson.getConstraintDefs());
+ serviceDef.setContextEnrichers(fromJson.getContextEnrichers());
+ serviceDef.setEnums(fromJson.getEnums());
+ serviceDef.setDataMaskDef(fromJson.getDataMaskDef());
+ serviceDef.setRowFilterDef(fromJson.getRowFilterDef());
+
+ return true;
+ }
+
+ private void loadChildTables(V serviceDef, T xServiceDef) {
Long serviceDefId = xServiceDef.getId();
List<XXServiceConfigDef> xConfigs =
daoMgr.getXXServiceConfigDef().findByServiceDefId(serviceDefId);
@@ -619,8 +678,6 @@ protected V populateViewBean(T xServiceDef) {
serviceDef.setAccessTypes(accessTypes);
}
-
serviceDef.setMarkerAccessTypes(ServiceDefUtil.getMarkerAccessTypes(serviceDef.getAccessTypes()));
-
List<XXPolicyConditionDef> xPolicyConditions =
daoMgr.getXXPolicyConditionDef().findByServiceDefId(serviceDefId);
if (!stringUtil.isEmpty(xPolicyConditions)) {
@@ -713,12 +770,6 @@ protected V populateViewBean(T xServiceDef) {
serviceDef.setDataMaskDef(dataMaskDef);
serviceDef.setRowFilterDef(rowFilterDef);
-
- addImplicitConditionExpressionIfNeeded(serviceDef);
-
- ServiceDefUtil.normalize(serviceDef);
-
- return serviceDef;
}
protected Map<String, String> jsonStringToMap(String jsonStr) {
diff --git
a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
index 5a36e7f29..fc1106a82 100644
--- a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
+++ b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
@@ -116,6 +116,7 @@
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
@@ -284,7 +285,11 @@ public void test11createServiceDef() throws Exception {
List<XXResourceDef> xResourceDefs = new ArrayList<>();
xResourceDefs.add(xResourceDef);
- RangerServiceDef serviceDef = new RangerServiceDef();
+ RangerServiceDef serviceDef = new RangerServiceDef();
+ List<RangerConstraintDef> constraintDefs =
Collections.singletonList(constraintDef());
+
+ serviceDef.setConstraintDefs(constraintDefs);
+
Mockito.when(serviceDefService.create(serviceDef)).thenReturn(serviceDef);
Mockito.when(daoMgr.getXXServiceDef()).thenReturn(xServiceDefDao);
@@ -323,6 +328,8 @@ public void test11createServiceDef() throws Exception {
Assertions.assertEquals(dbServiceDef.getResources(),
serviceDef.getResources());
Mockito.verify(serviceDefService).getPopulatedViewObject(xServiceDef);
Mockito.verify(serviceDefService).create(serviceDef);
+ Mockito.verify(serviceDefService).buildDefText(xServiceDef,
constraintDefs);
+ Mockito.verify(xServiceDefDao).update(xServiceDef);
Mockito.verify(daoMgr).getXXServiceConfigDef();
Mockito.verify(daoMgr).getXXEnumDef();
Mockito.verify(daoMgr).getXXAccessTypeDef();
@@ -342,8 +349,11 @@ public void test12updateServiceDef() throws Exception {
XXDataMaskTypeDefDao xDataMaskDefDao =
Mockito.mock(XXDataMaskTypeDefDao.class);
XXServiceDao xServiceDao =
Mockito.mock(XXServiceDao.class);
- RangerServiceDef rangerServiceDef = rangerServiceDef();
- Long serviceDefId = rangerServiceDef.getId();
+ RangerServiceDef rangerServiceDef = rangerServiceDef();
+ Long serviceDefId = rangerServiceDef.getId();
+ List<RangerConstraintDef> constraintDefs =
Collections.singletonList(constraintDef());
+
+ rangerServiceDef.setConstraintDefs(constraintDefs);
List<XXServiceConfigDef> svcConfDefList = new ArrayList<>();
XXServiceConfigDef serviceConfigDefObj = new
XXServiceConfigDef();
@@ -444,6 +454,9 @@ public void test12updateServiceDef() throws Exception {
Assertions.assertEquals(dbServiceDef.getConfigs(),
rangerServiceDef.getConfigs());
Assertions.assertEquals(dbServiceDef.getVersion(),
rangerServiceDef.getVersion());
Assertions.assertEquals(dbServiceDef.getResources(),
rangerServiceDef.getResources());
+ // update() returns a different object, so this checks the request's
constraintDefs were kept
+ Mockito.verify(serviceDefService).buildDefText(xServiceDef,
constraintDefs);
+ Mockito.verify(xServiceDefDao).update(xServiceDef);
}
@Test
@@ -6961,6 +6974,25 @@ private RangerServiceDef rangerServiceDef() {
return rangerServiceDef;
}
+ private RangerConstraintDef constraintDef() {
+ RangerServiceDef.RangerConstraintParamDef approver = new
RangerServiceDef.RangerConstraintParamDef();
+
+ approver.setItemId(1L);
+ approver.setName("approver");
+ approver.setType("string");
+ approver.setMandatory(true);
+
+ RangerConstraintDef constraintDef = new RangerConstraintDef();
+
+ constraintDef.setItemId(1L);
+ constraintDef.setName("requireApproval");
+ constraintDef.setResources(Collections.singletonList("tool"));
+ constraintDef.setAccessTypes(Collections.singletonList("execute"));
+ constraintDef.setParameters(Collections.singletonList(approver));
+
+ return constraintDef;
+ }
+
private RangerService rangerService() {
Map<String, String> configs = new HashMap<>();
configs.put("username", "servicemgr");
diff --git
a/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForServiceDefJson_J10067.java
b/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForServiceDefJson_J10067.java
new file mode 100644
index 000000000..b306d823f
--- /dev/null
+++
b/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForServiceDefJson_J10067.java
@@ -0,0 +1,113 @@
+/*
+ * 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.patch;
+
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.db.XXServiceDefDao;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.service.RangerServiceDefService;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+@ExtendWith(MockitoExtension.class)
+public class TestPatchForServiceDefJson_J10067 {
+ private RangerDaoManager daoMgr;
+ private XXServiceDefDao xServiceDefDao;
+ private RangerServiceDefService serviceDefService;
+ private PatchForServiceDefJson_J10067 patch;
+
+ @BeforeEach
+ public void setUp() {
+ daoMgr = Mockito.mock(RangerDaoManager.class);
+ xServiceDefDao = Mockito.mock(XXServiceDefDao.class);
+ serviceDefService = Mockito.mock(RangerServiceDefService.class);
+
+ PlatformTransactionManager txManager =
Mockito.mock(PlatformTransactionManager.class);
+
+
Mockito.lenient().when(txManager.getTransaction(Mockito.any())).thenReturn(Mockito.mock(TransactionStatus.class));
+ Mockito.when(daoMgr.getXXServiceDef()).thenReturn(xServiceDefDao);
+
+ patch = new PatchForServiceDefJson_J10067();
+ patch.daoMgr = daoMgr;
+ patch.serviceDefService = serviceDefService;
+ patch.txManager = txManager;
+ }
+
+ @Test
+ public void testStoresJsonOnlyForServiceDefsWithoutIt() {
+ XXServiceDef withoutJson = serviceDef(1L, "hive", null);
+ XXServiceDef withJson = serviceDef(2L, "hdfs",
"{\"name\":\"hdfs\"}");
+
+ Mockito.when(xServiceDefDao.getAll()).thenReturn(new
ArrayList<>(Arrays.asList(withoutJson, withJson)));
+ Mockito.when(xServiceDefDao.getById(1L)).thenReturn(withoutJson);
+ Mockito.when(xServiceDefDao.getById(2L)).thenReturn(withJson);
+ Mockito.when(serviceDefService.buildDefText(withoutJson,
null)).thenReturn("{\"name\":\"hive\"}");
+
+ patch.execLoad();
+
+ Assertions.assertEquals("{\"name\":\"hive\"}",
withoutJson.getDefText());
+ Assertions.assertEquals("{\"name\":\"hdfs\"}", withJson.getDefText());
+ Mockito.verify(xServiceDefDao).update(withoutJson);
+ Mockito.verify(xServiceDefDao, Mockito.never()).update(withJson);
+ Mockito.verify(serviceDefService,
Mockito.never()).buildDefText(Mockito.eq(withJson), Mockito.any());
+ }
+
+ @Test
+ public void testFailsWhenJsonCannotBeBuilt() {
+ XXServiceDef withoutJson = serviceDef(1L, "hive", null);
+
+ Mockito.when(xServiceDefDao.getAll()).thenReturn(new
ArrayList<>(Collections.singletonList(withoutJson)));
+ Mockito.when(xServiceDefDao.getById(1L)).thenReturn(withoutJson);
+ Mockito.when(serviceDefService.buildDefText(withoutJson,
null)).thenReturn(null);
+
+ Assertions.assertThrows(RuntimeException.class, () ->
patch.execLoad());
+ Mockito.verify(xServiceDefDao, Mockito.never()).update(Mockito.any());
+ }
+
+ @Test
+ public void testNoServiceDefs() {
+ Mockito.when(xServiceDefDao.getAll()).thenReturn(new ArrayList<>());
+
+ patch.execLoad();
+ patch.printStats();
+
+ Mockito.verify(xServiceDefDao, Mockito.never()).update(Mockito.any());
+ }
+
+ private static XXServiceDef serviceDef(Long id, String name, String
defText) {
+ XXServiceDef ret = new XXServiceDef();
+
+ ret.setId(id);
+ ret.setName(name);
+ ret.setDefText(defText);
+
+ return ret;
+ }
+}
diff --git
a/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefService.java
b/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefService.java
index 41d0be2d9..a86338b4a 100644
---
a/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefService.java
+++
b/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefService.java
@@ -18,8 +18,10 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig;
+import org.apache.ranger.authorization.utils.JsonUtils;
import org.apache.ranger.biz.RangerBizUtil;
import org.apache.ranger.common.ContextUtil;
+import org.apache.ranger.common.JSONUtil;
import org.apache.ranger.common.PropertiesUtil;
import org.apache.ranger.common.StringUtil;
import org.apache.ranger.common.UserSessionBase;
@@ -50,6 +52,7 @@
import org.apache.ranger.entity.XXServiceDefWithAssignedId;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef;
@@ -71,6 +74,7 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -85,6 +89,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -911,6 +916,202 @@ public void testValidateForUpdate() throws
NoSuchMethodException {
}
}
+ @Test
+ public void test6PopulateViewBeanLoadsConstraintDefs() throws Exception {
+ serviceDefService.jsonUtil = new JSONUtil();
+
+ RangerConstraintDef constraintDef = new RangerConstraintDef();
+ constraintDef.setItemId(4L);
+ constraintDef.setName("requireApproval");
+ constraintDef.setResources(Arrays.asList("database", "udf"));
+ constraintDef.setAccessTypes(Collections.singletonList("select"));
+ RangerServiceDef.RangerConstraintParamDef approver = new
RangerServiceDef.RangerConstraintParamDef();
+ approver.setItemId(1L);
+ approver.setName("approver");
+ approver.setType("string");
+ approver.setMandatory(true);
+ constraintDef.getParameters().add(approver);
+
+ RangerServiceDef jsonBody = new RangerServiceDef();
+ jsonBody.setName("json-name");
+ jsonBody.getConstraintDefs().add(constraintDef);
+
+ XXServiceDef serviceDef = serviceDef();
+ serviceDef.setAddedByUserId(null);
+ serviceDef.setUpdatedByUserId(null);
+ serviceDef.setName("hdfs");
+ serviceDef.setDefOptions("{}");
+ serviceDef.setDefText(serviceDefService.objectToJson(jsonBody));
+
+ RangerServiceDef loaded =
serviceDefService.populateViewBean(serviceDef);
+
+ assertNotNull(loaded.getConstraintDefs());
+ assertEquals(serviceDef.getName(), loaded.getName());
+ assertEquals(1, loaded.getConstraintDefs().size());
+ assertEquals(Long.valueOf(4L),
loaded.getConstraintDefs().get(0).getItemId());
+ assertEquals("requireApproval",
loaded.getConstraintDefs().get(0).getName());
+ assertEquals(Arrays.asList("database", "udf"),
loaded.getConstraintDefs().get(0).getResources());
+ assertEquals(Collections.singletonList("select"),
loaded.getConstraintDefs().get(0).getAccessTypes());
+ assertEquals("approver",
loaded.getConstraintDefs().get(0).getParameters().get(0).getName());
+ assertEquals("string",
loaded.getConstraintDefs().get(0).getParameters().get(0).getType());
+ }
+
+ @Test
+ public void testPopulateViewBeanReadsDefText() {
+ mockBaseFieldsForPopulateViewBean();
+
+ RangerResourceDef tool = new RangerResourceDef();
+ tool.setItemId(1L);
+ tool.setName("tool");
+ tool.setLevel(10);
+
+ RangerAccessTypeDef execute = new RangerAccessTypeDef();
+ execute.setItemId(1L);
+ execute.setName("execute");
+
+ RangerServiceDef stored = new RangerServiceDef();
+ stored.setName("stale-name-in-json");
+ stored.setResources(Collections.singletonList(tool));
+ stored.setAccessTypes(Collections.singletonList(execute));
+ stored.setConstraintDefs(Collections.singletonList(constraintDef()));
+
+ XXServiceDef xServiceDef = serviceDef();
+ xServiceDef.setName("agent");
+ xServiceDef.setDefOptions("{}");
+ xServiceDef.setDefText(JsonUtils.objectToJson(stored));
+
+ RangerServiceDef loaded =
serviceDefService.populateViewBean(xServiceDef);
+
+ assertEquals("agent", loaded.getName());
+ assertEquals(1, loaded.getResources().size());
+ assertEquals("tool", loaded.getResources().get(0).getName());
+ assertEquals("execute", loaded.getAccessTypes().get(0).getName());
+ assertEquals(1, loaded.getConstraintDefs().size());
+ assertEquals("requireApproval",
loaded.getConstraintDefs().get(0).getName());
+ assertEquals(Collections.singletonList("tool"),
loaded.getConstraintDefs().get(0).getResources());
+ assertEquals("approver",
loaded.getConstraintDefs().get(0).getParameters().get(0).getName());
+ verify(daoMgr, never()).getXXResourceDef();
+ verify(daoMgr, never()).getXXAccessTypeDef();
+ verify(daoMgr, never()).getXXServiceConfigDef();
+ }
+
+ @Test
+ public void testPopulateViewBeanFallsBackToChildTables() {
+ mockBaseFieldsForPopulateViewBean();
+ mockEmptyChildTables(Id);
+
+ XXServiceDef xServiceDef = serviceDef();
+ xServiceDef.setDefOptions("{}");
+ xServiceDef.setDefText("not-a-json");
+
+ RangerServiceDef loaded =
serviceDefService.populateViewBean(xServiceDef);
+
+ assertNotNull(loaded);
+ assertTrue(loaded.getConstraintDefs().isEmpty());
+ verify(daoMgr).getXXResourceDef();
+ verify(daoMgr).getXXAccessTypeDef();
+ }
+
+ @Test
+ public void testBuildDefTextIncludesConstraintDefsAndNoDerivedValues() {
+ serviceDefService.stringUtil = new StringUtil();
+ serviceDefService.jsonUtil = new JSONUtil();
+
+ mockEmptyChildTables(Id);
+
+ XXServiceDef xServiceDef = serviceDef();
+ xServiceDef.setName("agent");
+ xServiceDef.setDefOptions("{\"custom\":\"value\"}");
+
+ String defText = serviceDefService.buildDefText(xServiceDef,
Collections.singletonList(constraintDef()));
+
+ assertNotNull(defText);
+ assertFalse(defText.contains("markerAccessTypes"));
+
assertFalse(defText.contains(RangerServiceDef.OPTION_ENABLE_DENY_AND_EXCEPTIONS_IN_POLICIES));
+
+ RangerServiceDef stored = JsonUtils.jsonToObject(defText,
RangerServiceDef.class);
+
+ assertNotNull(stored);
+ assertEquals("agent", stored.getName());
+ assertEquals("value", stored.getOptions().get("custom"));
+ assertEquals(1, stored.getConstraintDefs().size());
+ assertEquals("requireApproval",
stored.getConstraintDefs().get(0).getName());
+ assertEquals(Arrays.asList("execute"),
stored.getConstraintDefs().get(0).getAccessTypes());
+ }
+
+ @Test
+ public void testBuildDefTextWithoutConstraintDefs() {
+ serviceDefService.stringUtil = new StringUtil();
+
+ mockEmptyChildTables(Id);
+
+ String defText =
serviceDefService.buildDefText(serviceDef(), null);
+ RangerServiceDef stored = JsonUtils.jsonToObject(defText,
RangerServiceDef.class);
+
+ assertNotNull(stored);
+ assertTrue(stored.getConstraintDefs() == null ||
stored.getConstraintDefs().isEmpty());
+ }
+
+ private void mockBaseFieldsForPopulateViewBean() {
+ serviceDefService.bizUtil = Mockito.mock(RangerBizUtil.class);
+ serviceDefService.stringUtil = new StringUtil();
+ serviceDefService.jsonUtil = new JSONUtil();
+
+ XXPortalUserDao xPortalUserDao = Mockito.mock(XXPortalUserDao.class);
+ XXPortalUser portalUser = new XXPortalUser();
+
+ portalUser.setId(Id);
+ portalUser.setFirstName("Admin");
+
+
Mockito.lenient().when(daoMgr.getXXPortalUser()).thenReturn(xPortalUserDao);
+
Mockito.lenient().when(xPortalUserDao.getById(Id)).thenReturn(portalUser);
+ }
+
+ private void mockEmptyChildTables(Long serviceDefId) {
+ XXServiceConfigDefDao xServiceConfigDefDao =
Mockito.mock(XXServiceConfigDefDao.class);
+ XXResourceDefDao xResourceDefDao =
Mockito.mock(XXResourceDefDao.class);
+ XXAccessTypeDefDao xAccessTypeDefDao =
Mockito.mock(XXAccessTypeDefDao.class);
+ XXAccessTypeDefGrantsDao xAccessTypeDefGrantsDao =
Mockito.mock(XXAccessTypeDefGrantsDao.class);
+ XXPolicyConditionDefDao xPolicyConditionDefDao =
Mockito.mock(XXPolicyConditionDefDao.class);
+ XXContextEnricherDefDao xContextEnricherDefDao =
Mockito.mock(XXContextEnricherDefDao.class);
+ XXEnumDefDao xEnumDefDao =
Mockito.mock(XXEnumDefDao.class);
+ XXDataMaskTypeDefDao xDataMaskTypeDefDao =
Mockito.mock(XXDataMaskTypeDefDao.class);
+
+
Mockito.when(daoMgr.getXXServiceConfigDef()).thenReturn(xServiceConfigDefDao);
+
Mockito.when(xServiceConfigDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+ Mockito.when(daoMgr.getXXResourceDef()).thenReturn(xResourceDefDao);
+
Mockito.when(xResourceDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+
Mockito.when(daoMgr.getXXAccessTypeDef()).thenReturn(xAccessTypeDefDao);
+
Mockito.when(xAccessTypeDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+
Mockito.when(daoMgr.getXXAccessTypeDefGrants()).thenReturn(xAccessTypeDefGrantsDao);
+
Mockito.when(xAccessTypeDefGrantsDao.findImpliedGrantsByServiceDefId(serviceDefId)).thenReturn(Collections.emptyMap());
+
Mockito.when(daoMgr.getXXPolicyConditionDef()).thenReturn(xPolicyConditionDefDao);
+
Mockito.when(xPolicyConditionDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+
Mockito.when(daoMgr.getXXContextEnricherDef()).thenReturn(xContextEnricherDefDao);
+
Mockito.when(xContextEnricherDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+ Mockito.when(daoMgr.getXXEnumDef()).thenReturn(xEnumDefDao);
+
Mockito.when(xEnumDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+
Mockito.when(daoMgr.getXXDataMaskTypeDef()).thenReturn(xDataMaskTypeDefDao);
+
Mockito.when(xDataMaskTypeDefDao.findByServiceDefId(serviceDefId)).thenReturn(new
ArrayList<>());
+ }
+
+ private RangerConstraintDef constraintDef() {
+ RangerServiceDef.RangerConstraintParamDef approver = new
RangerServiceDef.RangerConstraintParamDef();
+ approver.setItemId(1L);
+ approver.setName("approver");
+ approver.setType("string");
+ approver.setMandatory(true);
+
+ RangerConstraintDef ret = new RangerConstraintDef();
+ ret.setItemId(1L);
+ ret.setName("requireApproval");
+ ret.setResources(Collections.singletonList("tool"));
+ ret.setAccessTypes(Collections.singletonList("execute"));
+ ret.setParameters(Collections.singletonList(approver));
+
+ return ret;
+ }
+
private boolean hasActionMatchesCondition(RangerServiceDef serviceDef) {
if (serviceDef.getPolicyConditions() == null) {
return false;
diff --git
a/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefServiceBase.java
b/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefServiceBase.java
index b58f047c7..e9029b360 100644
---
a/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefServiceBase.java
+++
b/security-admin/src/test/java/org/apache/ranger/service/TestRangerServiceDefServiceBase.java
@@ -38,6 +38,8 @@
import org.apache.ranger.entity.XXServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintDef;
+import
org.apache.ranger.plugin.model.RangerServiceDef.RangerConstraintParamDef;
import
org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
@@ -62,9 +64,12 @@
import javax.ws.rs.WebApplicationException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -589,6 +594,94 @@ public void test21searchRangerServiceDefs() {
Assertions.assertNotNull(dbRangerServiceDefList);
}
+ @Test
+ public void test22mapViewToEntityBeanLeavesDefTextUnset() {
+ RangerServiceDef view = rangerServiceDef();
+ view.setGuid("column-guid");
+ view.setName("hdfs");
+ view.getConstraintDefs().add(constraintDef());
+
+ XXServiceDef stored =
rangerServiceDefService.mapViewToEntityBean(view, serviceDef(), 1);
+
+ Assertions.assertNull(stored.getDefText());
+ }
+
+ @Test
+ public void test23populateViewBeanReadsDefTextWithoutOverwritingColumns()
throws Exception {
+ JSONUtil jsonUtil = new JSONUtil();
+ rangerServiceDefService.jsonUtil = jsonUtil;
+
+ RangerServiceDef jsonBody = new RangerServiceDef();
+ jsonBody.setName("json-name");
+ jsonBody.setGuid("json-guid");
+ jsonBody.setLabel("json-label");
+ jsonBody.setDescription("json-description");
+ Map<String, String> jsonOptions = new HashMap<>();
+ jsonOptions.put("fromJson", "yes");
+ jsonBody.setOptions(jsonOptions);
+ jsonBody.getConstraintDefs().add(constraintDef());
+
+ XXServiceDef row = serviceDef();
+ row.setAddedByUserId(null);
+ row.setUpdatedByUserId(null);
+ row.setName("hdfs");
+ row.setGuid("column-guid");
+ row.setLabel("column-label");
+ row.setDescription("column-description");
+ row.setDefOptions("{\"stored\":\"yes\"}");
+ row.setDefText(jsonUtil.writeObjectAsString(jsonBody));
+
+ RangerServiceDef loaded =
rangerServiceDefService.populateViewBean(row);
+
+ Assertions.assertEquals("hdfs", loaded.getName());
+ Assertions.assertEquals("column-guid", loaded.getGuid());
+ Assertions.assertEquals("column-label", loaded.getLabel());
+ Assertions.assertEquals("column-description", loaded.getDescription());
+ Assertions.assertEquals("yes", loaded.getOptions().get("stored"));
+ Assertions.assertNull(loaded.getOptions().get("fromJson"));
+ Assertions.assertEquals(1, loaded.getConstraintDefs().size());
+ Assertions.assertEquals("requireApproval",
loaded.getConstraintDefs().get(0).getName());
+ Assertions.assertEquals(Arrays.asList("database", "udf"),
loaded.getConstraintDefs().get(0).getResources());
+ Assertions.assertEquals(Collections.singletonList("select"),
loaded.getConstraintDefs().get(0).getAccessTypes());
+ Assertions.assertEquals("approver",
loaded.getConstraintDefs().get(0).getParameters().get(0).getName());
+ Assertions.assertEquals("string",
loaded.getConstraintDefs().get(0).getParameters().get(0).getType());
+ Assertions.assertEquals("authType",
loaded.getConstraintDefs().get(0).getParameters().get(1).getSubType());
+ }
+
+ private RangerConstraintDef constraintDef() {
+ RangerConstraintParamDef approver = new RangerConstraintParamDef();
+ approver.setItemId(1L);
+ approver.setName("approver");
+ approver.setType("string");
+ approver.setMandatory(true);
+
+ RangerConstraintParamDef mode = new RangerConstraintParamDef();
+ mode.setItemId(2L);
+ mode.setName("mode");
+ mode.setType("enum");
+ mode.setSubType("authType");
+ mode.setMandatory(false);
+ mode.setDefaultValue("simple");
+
+ List<String> resources = new ArrayList<>();
+ resources.add("database");
+ resources.add("udf");
+ List<String> accessTypes = new ArrayList<>();
+ accessTypes.add("select");
+ List<RangerConstraintParamDef> parameters = new ArrayList<>();
+ parameters.add(approver);
+ parameters.add(mode);
+
+ RangerConstraintDef constraintDef = new RangerConstraintDef();
+ constraintDef.setItemId(4L);
+ constraintDef.setName("requireApproval");
+ constraintDef.setResources(resources);
+ constraintDef.setAccessTypes(accessTypes);
+ constraintDef.setParameters(parameters);
+
+ return constraintDef;
+ }
+
private RangerServiceDef rangerServiceDef() {
List<RangerServiceConfigDef> configs = new ArrayList<>();
List<RangerResourceDef> resources = new ArrayList<>();