You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2015/03/13 00:27:08 UTC

incubator-ranger git commit: RANGER-299 Service def validations; RANGER-304 validation does several checks in case-insensitive manner

Repository: incubator-ranger
Updated Branches:
  refs/heads/master 4d1abc89c -> 6e9f2a3b5


RANGER-299 Service def validations; RANGER-304 validation does several checks in case-insensitive manner

Conflicts:
	security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/6e9f2a3b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/6e9f2a3b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/6e9f2a3b

Branch: refs/heads/master
Commit: 6e9f2a3b5a9cc2a04927ca6a99f8c3ec93f1891b
Parents: 4d1abc8
Author: Alok Lal <al...@hortonworks.com>
Authored: Thu Mar 5 14:55:18 2015 -0800
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Mar 12 16:13:03 2015 -0700

----------------------------------------------------------------------
 .../ranger/rest/RangerPolicyValidator.java      |  26 +-
 .../ranger/rest/RangerServiceDefValidator.java  | 365 +++++++++++++++++++
 .../ranger/rest/RangerServiceValidator.java     |  31 +-
 .../org/apache/ranger/rest/RangerValidator.java |  73 +++-
 .../ranger/rest/RangerValidatorFactory.java     |   4 +
 .../org/apache/ranger/rest/ServiceREST.java     |   6 +
 .../ranger/rest/TestRangerPolicyValidator.java  |  15 +-
 .../rest/TestRangerServiceDefValidator.java     | 353 ++++++++++++++++++
 .../apache/ranger/rest/TestRangerValidator.java | 162 +++++++-
 .../rest/TestServiceRESTForValidation.java      | 133 ++++++-
 .../apache/ranger/rest/ValidationTestUtils.java |  60 +++
 11 files changed, 1167 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/RangerPolicyValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RangerPolicyValidator.java b/security-admin/src/main/java/org/apache/ranger/rest/RangerPolicyValidator.java
index 941bb21..281b32d 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RangerPolicyValidator.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerPolicyValidator.java
@@ -29,7 +29,7 @@ public class RangerPolicyValidator extends RangerValidator {
 
 	public void validate(RangerPolicy policy, Action action) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug(String.format("==> RangerValidator.validate(%s, %s)", policy, action));
+			LOG.debug(String.format("==> RangerPolicyValidator.validate(%s, %s)", policy, action));
 		}
 
 		List<ValidationFailureDetails> failures = new ArrayList<ValidationFailureDetails>();
@@ -42,7 +42,7 @@ public class RangerPolicyValidator extends RangerValidator {
 			}
 		} finally {
 			if(LOG.isDebugEnabled()) {
-				LOG.debug(String.format("<== RangerValidator.validate(%s, %s): %s, reason[%s]", policy, action, valid, message));
+				LOG.debug(String.format("<== RangerPolicyValidator.validate(%s, %s): %s, reason[%s]", policy, action, valid, message));
 			}
 		}
 	}
@@ -151,7 +151,7 @@ public class RangerPolicyValidator extends RangerValidator {
 						failures.add(new ValidationFailureDetailsBuilder()
 							.field("id/name")
 							.isSemanticallyIncorrect()
-							.becauseOf("id/name conflict: policy already exists with name[" + policyName + "], its id is[" + policies.iterator().next().getId() + "]")
+							.becauseOf("id/name conflict: another policy already exists with name[" + policyName + "], its id is[" + policies.iterator().next().getId() + "]")
 							.build());
 						valid = false;
 					}
@@ -396,17 +396,15 @@ public class RangerPolicyValidator extends RangerValidator {
 					.becauseOf("policy items access type's name was null/empty/blank")
 					.build());
 				valid = false;
-			} else {
-				if (!accessTypes.contains(accessType)) {
-					String message = String.format("access type[%s] not among valid types for service[%s]", accessType, accessTypes);
-					LOG.debug(message);
-					failures.add(new ValidationFailureDetailsBuilder()
-						.field("policy item access type")
-						.isSemanticallyIncorrect()
-						.becauseOf(message)
-						.build());
-					valid = false;
-				}
+			} else if (!accessTypes.contains(accessType.toLowerCase())) {
+				String message = String.format("access type[%s] not among valid types for service[%s]", accessType, accessTypes);
+				LOG.debug(message);
+				failures.add(new ValidationFailureDetailsBuilder()
+					.field("policy item access type")
+					.isSemanticallyIncorrect()
+					.becauseOf(message)
+					.build());
+				valid = false;
 			}
 			Boolean isAllowed = access.getIsAllowed();
 			// it can be null (which is treated as allowed) but not false

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceDefValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceDefValidator.java b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceDefValidator.java
new file mode 100644
index 0000000..a84f68a
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceDefValidator.java
@@ -0,0 +1,365 @@
+package org.apache.ranger.rest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+
+import com.google.common.collect.Sets;
+
+public class RangerServiceDefValidator extends RangerValidator {
+
+	private static final Log LOG = LogFactory.getLog(RangerServiceDefValidator.class);
+
+	public RangerServiceDefValidator(ServiceStore store) {
+		super(store);
+	}
+
+	public void validate(final RangerServiceDef serviceDef, final Action action) throws Exception {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("==> RangerServiceDefValidator.validate(%s, %s)", serviceDef, action));
+		}
+
+		List<ValidationFailureDetails> failures = new ArrayList<ValidationFailureDetails>();
+		boolean valid = isValid(serviceDef, action, failures);
+		String message = "";
+		try {
+			if (!valid) {
+				message = serializeFailures(failures);
+				throw new Exception(message);
+			}
+		} finally {
+			if(LOG.isDebugEnabled()) {
+				LOG.debug(String.format("<== RangerServiceDefValidator.validate(%s, %s): %s, reason[%s]", serviceDef, action, valid, message));
+			}
+		}
+	}
+
+	boolean isValid(final Long id, final Action action, final List<ValidationFailureDetails> failures) {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerServiceDefValidator.isValid(" + id + ")");
+		}
+
+		boolean valid = true;
+		if (action != Action.DELETE) {
+			failures.add(new ValidationFailureDetailsBuilder()
+				.isAnInternalError()
+				.becauseOf("unsupported action[" + action + "]; isValid(Long) is only supported for DELETE")
+				.build());
+			valid = false;
+		} else if (id == null) {
+			failures.add(new ValidationFailureDetailsBuilder()
+				.field("id")
+				.isMissing()
+				.build());
+			valid = false;
+		} else if (getServiceDef(id) == null) {
+			failures.add(new ValidationFailureDetailsBuilder()
+				.field("id")
+				.isSemanticallyIncorrect()
+				.becauseOf("no service def found for id[" + id + "]")
+				.build());
+			valid = false;
+		}
+
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerServiceDefValidator.isValid(" + id + "): " + valid);
+		}
+		return valid;
+	}
+	
+	boolean isValid(final RangerServiceDef serviceDef, final Action action, final List<ValidationFailureDetails> failures) {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerServiceDefValidator.isValid(" + serviceDef + ")");
+		}
+		
+		if (!(action == Action.CREATE || action == Action.UPDATE)) {
+			throw new IllegalArgumentException("isValid(RangerServiceDef, ...) is only supported for CREATE/UPDATE");
+		}
+		boolean valid = true;
+		if (serviceDef == null) {
+			String message = "service def object passed in was null";
+			LOG.debug(message);
+			failures.add(new ValidationFailureDetailsBuilder()
+				.field("service def")
+				.isMissing()
+				.becauseOf(message)
+				.build());
+			valid = false;
+		} else {
+			Long id = serviceDef.getId();
+			if (action == Action.UPDATE) { // id is ignored for CREATE
+				if (id == null) {
+					String message = "service def id was null/empty/blank"; 
+					LOG.debug(message);
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("id")
+						.isMissing()
+						.becauseOf(message)
+						.build());
+					valid = false;
+				} else if (getServiceDef(id) == null) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("id")
+						.isSemanticallyIncorrect()
+						.becauseOf("no service def exists with id[" + id +"]")
+						.build());
+					valid = false;
+				}
+			}
+			// validate the service def name
+			String name = serviceDef.getName();
+			boolean nameSpecified = StringUtils.isNotBlank(name);
+			if (!nameSpecified) {
+				String message = "service def name[" + name + "] was null/empty/blank"; 
+				LOG.debug(message);
+				failures.add(new ValidationFailureDetailsBuilder()
+					.field("name")
+					.isMissing()
+					.becauseOf(message)
+					.build());
+				valid = false;
+			} else {
+				RangerServiceDef otherServiceDef = getServiceDef(name);
+				if (otherServiceDef != null && action == Action.CREATE) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("name")
+						.isSemanticallyIncorrect()
+						.becauseOf("service def with the name[" + name + "] already exists")
+						.build());
+					valid = false;
+				} else if (otherServiceDef != null && otherServiceDef.getId() !=null && otherServiceDef.getId() != id) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("id/name")
+						.isSemanticallyIncorrect()
+						.becauseOf("id/name conflict: another service def already exists with name[" + name + "], its id is [" + otherServiceDef.getId() + "]")
+						.build());
+					valid = false;
+				}
+			}
+			if (CollectionUtils.isEmpty(serviceDef.getAccessTypes())) {
+				failures.add(new ValidationFailureDetailsBuilder()
+					.field("access types")
+					.isMissing()
+					.becauseOf("access types collection was null/empty")
+					.build());
+				valid = false;
+			} else {
+				valid = isValidAccessTypes(serviceDef.getAccessTypes(), failures) && valid;
+			}
+			if (CollectionUtils.isEmpty(serviceDef.getEnums())) {
+				LOG.debug("No enums specified on the service def.  Ok!");
+			} else {
+				valid = isValidEnums(serviceDef.getEnums(), failures) && valid;
+			}
+		}
+		
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerServiceDefValidator.isValid(" + serviceDef + "): " + valid);
+		}
+		return valid;
+	}
+
+	boolean isValidAccessTypes(final List<RangerAccessTypeDef> accessTypeDefs, final List<ValidationFailureDetails> failures) {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("==> RangerServiceDefValidator.isValidAccessTypes(%s, %s)", accessTypeDefs, failures));
+		}
+		
+		boolean valid = true;
+		if (CollectionUtils.isEmpty(accessTypeDefs)) {
+			LOG.debug("access type def collection is empty/null");
+		} else {
+			List<RangerAccessTypeDef> defsWithImpliedGrants = new ArrayList<RangerAccessTypeDef>();
+			Set<String> accessNames = new HashSet<String>();
+			for (RangerAccessTypeDef def : accessTypeDefs) {
+				String name = def.getName();
+				// name can't be null/empty/blank
+				if (StringUtils.isBlank(name)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("access type name")
+						.isMissing()
+						.becauseOf("access type name[" + name + "] is null/empty")
+						.build());
+					valid = false;
+				} else if (accessNames.contains(name.toLowerCase())) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("access type name")
+						.subField(name)
+						.isSemanticallyIncorrect()
+						.becauseOf("duplicate access type names in access types collection: [" + name + "]")
+						.build());
+					valid = false;
+				} else {
+					accessNames.add(name.toLowerCase()); // we have a new unique access type
+				}
+				if (CollectionUtils.isNotEmpty(def.getImpliedGrants())) {
+					defsWithImpliedGrants.add(def);
+				}
+			}
+			// validate implied grants
+			for (RangerAccessTypeDef def : defsWithImpliedGrants) {
+				Collection<String> impliedGrants = getImpliedGrants(def);
+				Set<String> unknownAccessTypes = Sets.difference(Sets.newHashSet(impliedGrants), accessNames);
+				if (!unknownAccessTypes.isEmpty()) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("implied grants")
+						.subField(unknownAccessTypes.iterator().next())  // we return just on item here.  Message has all unknow items
+						.isSemanticallyIncorrect()
+						.becauseOf("implied grant[" + impliedGrants + "] contains an unknown access types[" + unknownAccessTypes + "]")
+						.build());
+					valid = false;
+				}
+				// implied grant should not imply itself! 
+				String name = def.getName(); // note: this name could be null/blank/empty!
+				if (impliedGrants.contains(name)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("implied grants")
+						.subField(name)
+						.isSemanticallyIncorrect()
+						.becauseOf("implied grants list [" + impliedGrants + "] for access type[" + name + "] contains itself")
+						.build());
+					valid = false;
+				}
+			}
+		}
+		
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("<== RangerServiceDefValidator.isValidAccessTypes(%s, %s): %s", accessTypeDefs, failures, valid));
+		}
+		return valid;
+	}
+
+	boolean isValidEnums(List<RangerEnumDef> enumDefs, List<ValidationFailureDetails> failures) {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("==> RangerServiceDefValidator.isValidEnums(%s, %s)", enumDefs, failures));
+		}
+		
+		boolean valid = true;
+		if (CollectionUtils.isEmpty(enumDefs)) {
+			LOG.debug("enum def collection passed in was null/empty");
+		} else {
+			Set<String> enumNames = new HashSet<String>();
+			for (RangerEnumDef enumDef : enumDefs) {
+				if (enumDef == null) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("enum def")
+						.isMissing()
+						.becauseOf("An enum def in enums collection is null")
+						.build());
+					valid = false;
+				} else {
+					// enum-names must non-blank and be unique to a service definition
+					String enumName = enumDef.getName();
+					if (StringUtils.isBlank(enumName)) {
+						failures.add(new ValidationFailureDetailsBuilder()
+							.field("enum def name")
+							.isMissing()
+							.becauseOf("enum name [" + enumName + "] is null/empty")
+							.build());
+						valid = false;
+					} else if (enumNames.contains(enumName.toLowerCase())) {
+						failures.add(new ValidationFailureDetailsBuilder()
+							.field("enum def name")
+							.subField(enumName)
+							.isSemanticallyIncorrect()
+							.becauseOf("dumplicate enum name [" + enumName + "] found")
+							.build());
+						valid = false;
+					} else {
+						enumNames.add(enumName.toLowerCase());
+					}
+					// enum must contain at least one valid value and those values should be non-blank and distinct
+					if (CollectionUtils.isEmpty(enumDef.getElements())) {
+						failures.add(new ValidationFailureDetailsBuilder()
+							.field("enum values")
+							.subField(enumName)
+							.isMissing()
+							.becauseOf("enum [" + enumName + "] does not have any elements")
+							.build());
+						valid = false;
+					} else {
+						valid = isValidEnumElements(enumDef.getElements(), failures, enumName) && valid;
+						// default index should be valid
+						int defaultIndex = getEnumDefaultIndex(enumDef);
+						if (defaultIndex < 0 || defaultIndex >= enumDef.getElements().size()) { // max index is one less than the size of the elements list
+							failures.add(new ValidationFailureDetailsBuilder()
+								.field("enum default index")
+								.subField(enumName)
+								.isSemanticallyIncorrect()
+								.becauseOf("default index[" + defaultIndex + "] for enum [" + enumName + "] is invalid")
+								.build());
+							valid = false;
+						}
+					}
+				}
+			}
+		}
+		
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("<== RangerServiceDefValidator.isValidEnums(%s, %s): %s", enumDefs, failures, valid));
+		}
+		return valid;
+	}
+
+	boolean isValidEnumElements(List<RangerEnumElementDef> enumElementsDefs, List<ValidationFailureDetails> failures, String enumName) {
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("==> RangerServiceDefValidator.isValidEnums(%s, %s)", enumElementsDefs, failures));
+		}
+		
+		boolean valid = true;
+		if (CollectionUtils.isEmpty(enumElementsDefs)) {
+			LOG.debug("Enum elements list passed in was null/empty!");
+		} else {
+			// enum element names should be valid and distinct
+			Set<String> elementNames = new HashSet<String>();
+			for (RangerEnumElementDef elementDef : enumElementsDefs) {
+				if (elementDef == null) {
+					failures.add(new ValidationFailureDetailsBuilder()
+						.field("enum element")
+						.subField(enumName)
+						.isMissing()
+						.becauseOf("An enum element in enum element collection of enum [" + enumName + "] is null")
+						.build());
+					valid = false;
+				} else {
+					String elementName = elementDef.getName();
+					if (StringUtils.isBlank(elementName)) {
+						failures.add(new ValidationFailureDetailsBuilder()
+							.field("enum element name")
+							.subField(enumName)
+							.isMissing()
+							.becauseOf("Name of an element of enum [" + enumName + "] is null/empty[" + elementName + "]")
+							.build());
+						valid = false;
+					} else if (elementNames.contains(elementName.toLowerCase())) {
+						failures.add(new ValidationFailureDetailsBuilder()
+							.field("enum element name")
+							.subField(enumName)
+							.isSemanticallyIncorrect()
+							.becauseOf("dumplicate enum element name [" + elementName + "] found for enum[" + enumName + "]")
+							.build());
+						valid = false;
+					} else {
+						elementNames.add(elementName.toLowerCase());
+					}
+				}
+			}
+		}
+		
+		if(LOG.isDebugEnabled()) {
+			LOG.debug(String.format("<== RangerServiceDefValidator.isValidEnums(%s, %s): %s", enumElementsDefs, failures, valid));
+		}
+		return valid;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java
index 11e2682..8e02f25 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java
@@ -42,18 +42,21 @@ public class RangerServiceValidator extends RangerValidator {
 
 	public void validate(RangerService service, Action action) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerValidator.validate(" + service + ")");
+			LOG.debug(String.format("==> RangerServiceValidator.validate(%s, %s)", service, action));
 		}
 
 		List<ValidationFailureDetails> failures = new ArrayList<ValidationFailureDetails>();
-		if (isValid(service, action, failures)) {
+		boolean valid = isValid(service, action, failures);
+		String message = "";
+		try {
+			if (!valid) {
+				message = serializeFailures(failures);
+				throw new Exception(message);
+			}
+		} finally {
 			if(LOG.isDebugEnabled()) {
-				LOG.debug("<== RangerValidator.validate(" + service + "): valid");
+				LOG.debug(String.format("<== RangerServiceValidator.validate(%s, %s): %s, reason[%s]", service, action, valid, message));
 			}
-		} else {
-			String message = serializeFailures(failures);
-			LOG.debug("<== RangerValidator.validate(" + service + "): invalid, reason[" + message + "]");
-			throw new Exception(message);
 		}
 	}
 	
@@ -66,7 +69,7 @@ public class RangerServiceValidator extends RangerValidator {
 		if (action != Action.DELETE) {
 			failures.add(new ValidationFailureDetailsBuilder()
 				.isAnInternalError()
-				.becauseOf("isValid(Long) is only supported for DELETE")
+				.becauseOf("unsupported action[" + action + "]; isValid(Long) is only supported for DELETE")
 				.build());
 			valid = false;
 		} else if (id == null) {
@@ -133,7 +136,7 @@ public class RangerServiceValidator extends RangerValidator {
 			boolean nameSpecified = StringUtils.isNotBlank(name);
 			RangerServiceDef serviceDef = null;
 			if (!nameSpecified) {
-				String message = "service name was null/empty/blank[" + name + "]"; 
+				String message = "service name[" + name + "] was null/empty/blank"; 
 				LOG.debug(message);
 				failures.add(new ValidationFailureDetailsBuilder()
 					.field("name")
@@ -147,14 +150,14 @@ public class RangerServiceValidator extends RangerValidator {
 					failures.add(new ValidationFailureDetailsBuilder()
 						.field("name")
 						.isSemanticallyIncorrect()
-						.becauseOf("service already exists with name[" + name + "]")
+						.becauseOf("service with the name[" + name + "] already exists")
 						.build());
 					valid = false;
 				} else if (otherService != null && otherService.getId() !=null && otherService.getId() != id) {
 					failures.add(new ValidationFailureDetailsBuilder()
 						.field("id/name")
 						.isSemanticallyIncorrect()
-						.becauseOf("id/name conflict: service already exists with name[" + name + "], its id is [" + otherService.getId() + "]")
+						.becauseOf("id/name conflict: another service already exists with name[" + name + "], its id is [" + otherService.getId() + "]")
 						.build());
 					valid = false;
 				}
@@ -165,7 +168,7 @@ public class RangerServiceValidator extends RangerValidator {
 				failures.add(new ValidationFailureDetailsBuilder()
 					.field("type")
 					.isMissing()
-					.becauseOf("service def was null/empty/blank")
+					.becauseOf("service def [" + type + "] was null/empty/blank")
 					.build());
 				valid = false;
 			} else {
@@ -174,7 +177,7 @@ public class RangerServiceValidator extends RangerValidator {
 					failures.add(new ValidationFailureDetailsBuilder()
 						.field("type")
 						.isSemanticallyIncorrect()
-						.becauseOf("service def not found for type[" + type + "]")
+						.becauseOf("service def named[" + type + "] not found")
 						.build());
 					valid = false;
 				}
@@ -188,7 +191,7 @@ public class RangerServiceValidator extends RangerValidator {
 						.field("configuration")
 						.subField(missingParameters.iterator().next()) // we return any one parameter!
 						.isMissing()
-						.becauseOf("required configuration parameter is missing")
+						.becauseOf("required configuration parameter is missing; missing parameters: " + missingParameters)
 						.build());
 					valid = false;
 				}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java
index b6948dc..cec40fd 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java
@@ -21,6 +21,7 @@ package org.apache.ranger.rest;
 
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -36,6 +37,7 @@ import org.apache.ranger.plugin.model.RangerPolicy;
 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.RangerEnumDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
 import org.apache.ranger.plugin.store.ServiceStore;
@@ -149,6 +151,24 @@ public abstract class RangerValidator {
 		return result;
 	}
 
+	RangerServiceDef getServiceDef(Long id) {
+
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerValidator.getServiceDef(" + id + ")");
+		}
+		RangerServiceDef result = null;
+		try {
+			result = _store.getServiceDef(id);
+		} catch (Exception e) {
+			LOG.debug("Encountred exception while retrieving service def from service store!", e);
+		}
+		
+		if(LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerValidator.getServiceDef(" + id + "): " + result);
+		}
+		return result;
+	}
+
 	RangerServiceDef getServiceDef(String type) {
 		
 		if(LOG.isDebugEnabled()) {
@@ -262,7 +282,7 @@ public abstract class RangerValidator {
 					if (StringUtils.isBlank(accessType)) {
 						LOG.warn("Access type def name was null/empty/blank!");
 					} else {
-						accessTypes.add(accessType);
+						accessTypes.add(accessType.toLowerCase());
 					}
 				}
 			}
@@ -299,6 +319,11 @@ public abstract class RangerValidator {
 		return isEnabled;
 	}
 	
+	/**
+	 * Returns names of resource types set to lower-case to allow for case-insensitive comparison. 
+	 * @param serviceDef
+	 * @return
+	 */
 	Set<String> getMandatoryResourceNames(RangerServiceDef serviceDef) {
 		if(LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerValidator.getMandatoryResourceNames(" + serviceDef + ")");
@@ -320,7 +345,7 @@ public abstract class RangerValidator {
 						if (StringUtils.isBlank(resourceName)) {
 							LOG.warn("Resource def name was null/empty/blank!");
 						} else {
-							resourceNames.add(resourceName);
+							resourceNames.add(resourceName.toLowerCase());
 						}
 					}
 				}
@@ -352,7 +377,7 @@ public abstract class RangerValidator {
 					if (StringUtils.isBlank(resourceName)) {
 						LOG.warn("Resource def name was null/empty/blank!");
 					} else {
-						resourceNames.add(resourceName);
+						resourceNames.add(resourceName.toLowerCase());
 					}
 				}
 			}
@@ -364,11 +389,20 @@ public abstract class RangerValidator {
 		return resourceNames;
 	}
 	
+	/**
+	 * Returns the resource-types defined on the policy converted to lowe-case
+	 * @param policy
+	 * @return
+	 */
 	Set<String> getPolicyResources(RangerPolicy policy) {
 		if (policy == null || policy.getResources() == null || policy.getResources().isEmpty()) {
 			return new HashSet<String>();
 		} else {
-			return policy.getResources().keySet();
+			Set<String> result = new HashSet<String>();
+			for (String name : policy.getResources().keySet()) {
+				result.add(name.toLowerCase());
+			}
+			return result;
 		}
 	}
 
@@ -395,4 +429,35 @@ public abstract class RangerValidator {
 			return result;
 		}
 	}
+	
+	int getEnumDefaultIndex(RangerEnumDef enumDef) {
+		int index;
+		if (enumDef == null) {
+			index = -1;
+		} else if (enumDef.getDefaultIndex() == null) {
+			index = 0;
+		} else {
+			index = enumDef.getDefaultIndex();
+		}
+		return index;
+	}
+
+	Collection<String> getImpliedGrants(RangerAccessTypeDef def) {
+		if (def == null) {
+			return null;
+		} else if (CollectionUtils.isEmpty(def.getImpliedGrants())) {
+			return new ArrayList<String>();
+		} else {
+			List<String> result = new ArrayList<String>(def.getImpliedGrants().size());
+			for (String name : def.getImpliedGrants()) {
+				if (StringUtils.isBlank(name)) {
+					result.add(name); // could be null!
+				} else {
+					result.add(name.toLowerCase());
+				}
+			}
+			return result;
+		}
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java
index 01b0a7e..025595d 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java
@@ -30,4 +30,8 @@ public class RangerValidatorFactory {
 	public RangerPolicyValidator getPolicyValidator(ServiceDBStore store) {
 		return new RangerPolicyValidator(store);
 	}
+
+	public RangerServiceDefValidator getServiceDefValidator(ServiceDBStore store) {
+		return new RangerServiceDefValidator(store);
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index be52892..8f41288 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -119,6 +119,8 @@ public class ServiceREST {
 		RangerServiceDef ret = null;
 
 		try {
+			RangerServiceDefValidator validator = validatorFactory.getServiceDefValidator(svcStore);
+			validator.validate(serviceDef, Action.CREATE);
 			ret = svcStore.createServiceDef(serviceDef);
 		} catch(Exception excp) {
 			LOG.error("createServiceDef(" + serviceDef + ") failed", excp);
@@ -145,6 +147,8 @@ public class ServiceREST {
 		RangerServiceDef ret = null;
 
 		try {
+			RangerServiceDefValidator validator = validatorFactory.getServiceDefValidator(svcStore);
+			validator.validate(serviceDef, Action.UPDATE);
 			ret = svcStore.updateServiceDef(serviceDef);
 		} catch(Exception excp) {
 			LOG.error("updateServiceDef(" + serviceDef + ") failed", excp);
@@ -169,6 +173,8 @@ public class ServiceREST {
 		}
 
 		try {
+			RangerServiceDefValidator validator = validatorFactory.getServiceDefValidator(svcStore);
+			validator.validate(id, Action.DELETE);
 			svcStore.deleteServiceDef(id);
 		} catch(Exception excp) {
 			LOG.error("deleteServiceDef(" + id + ") failed", excp);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerPolicyValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerPolicyValidator.java b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerPolicyValidator.java
index 4e15753..c3fdf30 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerPolicyValidator.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerPolicyValidator.java
@@ -45,20 +45,20 @@ public class TestRangerPolicyValidator {
 				"groups", new String[] {"group1", "group2"},
 				"accesses", new String[] { "r", "w" },
 				"isAllowed", new Boolean[] { true, true }),
-			ImmutableMap.of(   // no users
+			ImmutableMap.of(   // no users, access type different case
 				"groups", new String[] {"group3", "group4"},
-				"accesses", new String[]{"w", "x"}, 
+				"accesses", new String[]{"W", "x"}, 
 				"isAllowed", new Boolean[] { true, true }),
 			ImmutableMap.of(   // no groups
 				"users", new String[] {"user3" ," user4"}, 
 				"accesses", new String[] { "r", "x" },
 				"isAllowed", new Boolean[] { true, true }),
-			ImmutableMap.of( // isallowed on access types is null
+			ImmutableMap.of( // isallowed on access types is null, case is different from that in definition
 				"users", new String[] {"user7" ," user6"},
 				"accesses", new String[] { "a" },
 				"isAllowed", new Boolean[] { null, null })
 	};
-	String[] accessTypes = new String[] { "r", "w", "x", "a" };
+	String[] accessTypes = new String[] { "r", "w", "x", "A" };  // mix of lower and upper case
 	String[] accessTypes_bad = new String[] { "r", "w", "xx", }; // two missing (x, a), one new that isn't on bad (xx)
 	
 	final Object[][] resourceDefData = new Object[][] {
@@ -69,7 +69,8 @@ public class TestRangerPolicyValidator {
 	
 	final Map<String, String[]> policyResourceMap_good = ImmutableMap.of(
 			"db", new String[] { "db1", "db2" },
-			"tbl", new String[] { "tbl1", "tbl2" } );
+			"TBL", new String[] { "tbl1", "tbl2" } ); // case should not matter
+	
 	final Map<String, String[]> policyResourceMap_bad = ImmutableMap.of(
 			"db", new String[] { "db1", "db2" },            // mandatory "tbl" missing
 			"col", new String[] { "col12", "col 1" },       // wrong format of value for "col"
@@ -424,9 +425,9 @@ public class TestRangerPolicyValidator {
 	public void test_isValidPolicyItemAccess_happyPath() {
 		
 		RangerPolicyItemAccess access = mock(RangerPolicyItemAccess.class);
-		when(access.getType()).thenReturn("anAccess"); // valid
+		when(access.getType()).thenReturn("an-Access"); // valid
 
-		Set<String> validAccesses = Sets.newHashSet(new String[] { "anAccess", "anotherAccess" });
+		Set<String> validAccesses = Sets.newHashSet(new String[] { "an-access", "another-access" });  // valid accesses should be lower-cased
 		
 		// both null or true access types are the same and valid
 		for (Boolean allowed : new Boolean[] { null, true } ) {

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceDefValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceDefValidator.java b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceDefValidator.java
new file mode 100644
index 0000000..b621673
--- /dev/null
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceDefValidator.java
@@ -0,0 +1,353 @@
+package org.apache.ranger.rest;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.rest.RangerValidator.Action;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class TestRangerServiceDefValidator {
+
+	@Before
+	public void setUp() throws Exception {
+		_store = mock(ServiceStore.class);
+		_validator = new RangerServiceDefValidator(_store);
+		_failures = new ArrayList<ValidationFailureDetails>();
+		_serviceDef = mock(RangerServiceDef.class);
+	}
+
+	final Action[] cu = new Action[] { Action.CREATE, Action.UPDATE };
+	
+	final Object[][] accessTypes_good = new Object[][] {
+			{ "read",  null },                                // ok, null implied grants
+			{ "write", new String[] {   } },                  // ok, empty implied grants
+			{ "admin", new String[] { "READ",  "write" } }    // ok, admin access implies read/write, access types are case-insensitive
+	};
+
+	final Map<String, String[]> enums_good = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" }
+	);
+	
+	@Test
+	public final void test_isValid_happyPath_create() throws Exception {
+		
+		// setup access types with implied access and couple of enums
+		List<RangerAccessTypeDef> accessTypeDefs = _utils.createAccessTypeDefs(accessTypes_good);
+		when(_serviceDef.getAccessTypes()).thenReturn(accessTypeDefs);
+		List<RangerEnumDef> enumDefs = _utils.createEnumDefs(enums_good);
+		when(_serviceDef.getEnums()).thenReturn(enumDefs);
+
+		// create: id is not relevant, name should not conflict 
+		when(_serviceDef.getId()).thenReturn(null); // id is not relevant for create
+		when(_serviceDef.getName()).thenReturn("aServiceDef"); // service has a name
+		when(_store.getServiceDefByName("aServiceDef")).thenReturn(null); // no name collision
+		assertTrue(_validator.isValid(_serviceDef, Action.CREATE, _failures));
+		assertTrue(_failures.isEmpty());
+		
+		// update: id should match existing service, name should not point to different service def
+		when(_serviceDef.getId()).thenReturn(5L);
+		RangerServiceDef existingServiceDef = mock(RangerServiceDef.class);
+		when(_store.getServiceDef(5L)).thenReturn(existingServiceDef);
+		assertTrue(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		assertTrue(_failures.isEmpty());
+		
+		// update: if name points to a service that it's id should be the same
+		RangerServiceDef anotherExistingServiceDef = mock(RangerServiceDef.class);
+		when(anotherExistingServiceDef.getId()).thenReturn(5L);
+		when(_store.getServiceDefByName("aServiceDef")).thenReturn(anotherExistingServiceDef);
+		assertTrue(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		assertTrue(_failures.isEmpty());
+	}
+	
+	@Test
+	public final void testIsValid_Long_failures() throws Exception {
+		Long id = null;
+		// passing in wrong action type 
+		boolean result = _validator.isValid((Long)null, Action.CREATE, _failures);
+		assertFalse(result);
+		_utils.checkFailureForInternalError(_failures);
+		// passing in null id is an error
+		_failures.clear(); assertFalse(_validator.isValid((Long)null, Action.DELETE, _failures));
+		_utils.checkFailureForMissingValue(_failures, "id");
+		// a service def with that id should exist, else it is an error
+		id = 3L;
+		when(_store.getServiceDef(id)).thenReturn(null);
+		_failures.clear(); assertFalse(_validator.isValid(id, Action.DELETE, _failures));
+		_utils.checkFailureForSemanticError(_failures, "id");
+		// happypath
+		when(_store.getServiceDef(id)).thenReturn(_serviceDef);
+		_failures.clear(); assertTrue(_validator.isValid(id, Action.DELETE, _failures));
+		assertTrue(_failures.isEmpty());
+	}
+
+	@Test
+	public final void testIsValid_failures_name() throws Exception {
+		// null service def and bad service def name
+		for (Action action : cu) {
+			// passing in null service def is an error
+			assertFalse(_validator.isValid((RangerServiceDef)null, action, _failures));
+			_utils.checkFailureForMissingValue(_failures, "service def");
+			// name should be valid
+			for (String name : new String[] { null, "", "  " }) {
+				when(_serviceDef.getName()).thenReturn(name);
+				_failures.clear(); assertFalse(_validator.isValid(_serviceDef, action, _failures));
+				_utils.checkFailureForMissingValue(_failures, "name");
+			}
+		}
+	}
+	
+	@Test
+	public final void testIsValid_failures_id() throws Exception {
+		// id is required for update
+		when(_serviceDef.getId()).thenReturn(null);
+		assertFalse(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		_utils.checkFailureForMissingValue(_failures, "id");
+		
+		// update: service should exist for the passed in id
+		Long id = 7L;
+		when(_serviceDef.getId()).thenReturn(id);
+		when(_store.getServiceDef(id)).thenReturn(null);
+		assertFalse(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		_utils.checkFailureForSemanticError(_failures, "id");
+
+		when(_store.getServiceDef(id)).thenThrow(new Exception());
+		assertFalse(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		_utils.checkFailureForSemanticError(_failures, "id");
+	}
+	
+	@Test
+	public final void testIsValid_failures_nameId_create() throws Exception {
+		// service shouldn't exist with the name
+		RangerServiceDef existingServiceDef = mock(RangerServiceDef.class);
+		when(_store.getServiceDefByName("existing-service")).thenReturn(existingServiceDef);
+		when(_serviceDef.getName()).thenReturn("existing-service");
+		_failures.clear(); assertFalse(_validator.isValid(_serviceDef, Action.CREATE, _failures));
+		_utils.checkFailureForSemanticError(_failures, "name");
+	}
+	
+	@Test
+	public final void testIsValid_failures_nameId_update() throws Exception {
+		
+		// update: if service exists with the same name then it can't point to a different service
+		Long id = 7L;
+		when(_serviceDef.getId()).thenReturn(id);
+		RangerServiceDef existingServiceDef = mock(RangerServiceDef.class);
+		when(existingServiceDef.getId()).thenReturn(id);
+		when(_store.getServiceDef(id)).thenReturn(existingServiceDef);
+		
+		String name = "aServiceDef";
+		when(_serviceDef.getName()).thenReturn(name);
+		RangerServiceDef anotherExistingServiceDef = mock(RangerServiceDef.class);
+		Long anotherId = 49L;
+		when(anotherExistingServiceDef.getId()).thenReturn(anotherId);
+		when(_store.getServiceDefByName(name)).thenReturn(anotherExistingServiceDef);
+		
+		assertFalse(_validator.isValid(_serviceDef, Action.UPDATE, _failures));
+		_utils.checkFailureForSemanticError(_failures, "id/name");
+	}
+
+	final Object[][] accessTypes_bad_unknownType = new Object[][] {
+			{ "read",  null },                                // ok, null implied grants
+			{ "write", new String[] {   } },                  // ok, empty implied grants
+			{ "admin", new String[] { "ReaD",  "execute" } }  // non-existent access type (execute), read is good (case should not matter)
+	};
+
+	final Object[][] accessTypes_bad_selfReference = new Object[][] {
+			{ "read",  null },                                // ok, null implied grants
+			{ "write", new String[] {   } },                  // ok, empty implied grants
+			{ "admin", new String[] { "write", "admin" } }  // non-existent access type (execute)
+	};
+
+	@Test
+	public final void test_isValidAccessTypes_happyPath() {
+		List<RangerAccessTypeDef> input = _utils.createAccessTypeDefs(accessTypes_good);
+		assertTrue(_validator.isValidAccessTypes(input, _failures));
+		assertTrue(_failures.isEmpty());
+	}
+	
+	@Test
+	public final void test_isValidAccessTypes_failures() {
+		// sending in empty null access type defs is ok
+		assertTrue(_validator.isValidAccessTypes(null, _failures));
+		assertTrue(_failures.isEmpty());
+		
+		List<RangerAccessTypeDef> input = new ArrayList<RangerAccessTypeDef>();
+		_failures.clear(); assertTrue(_validator.isValidAccessTypes(input, _failures));
+		assertTrue(_failures.isEmpty());
+
+		// null/empty access types
+		List<RangerAccessTypeDef> accessTypeDefs = _utils.createAccessTypeDefs(new String[] { null, "", "		" });
+		_failures.clear(); assertFalse(_validator.isValidAccessTypes(accessTypeDefs, _failures));
+		_utils.checkFailureForMissingValue(_failures, "access type name");
+		
+		// duplicate access types
+		accessTypeDefs = _utils.createAccessTypeDefs(new String[] { "read", "write", "execute", "read" } );
+		_failures.clear(); assertFalse(_validator.isValidAccessTypes(accessTypeDefs, _failures));
+		_utils.checkFailureForSemanticError(_failures, "access type name", "read");
+		
+		// duplicate access types - case-insensitive
+		accessTypeDefs = _utils.createAccessTypeDefs(new String[] { "read", "write", "execute", "READ" } );
+		_failures.clear(); assertFalse(_validator.isValidAccessTypes(accessTypeDefs, _failures));
+		_utils.checkFailureForSemanticError(_failures, "access type name", "READ");
+		
+		// unknown access type in implied grants list
+		accessTypeDefs = _utils.createAccessTypeDefs(accessTypes_bad_unknownType);
+		_failures.clear(); assertFalse(_validator.isValidAccessTypes(accessTypeDefs, _failures));
+		_utils.checkFailureForSemanticError(_failures, "implied grants", "execute");
+		
+		// access type with implied grant referring to itself
+		accessTypeDefs = _utils.createAccessTypeDefs(accessTypes_bad_selfReference);
+		_failures.clear(); assertFalse(_validator.isValidAccessTypes(accessTypeDefs, _failures));
+		_utils.checkFailureForSemanticError(_failures, "implied grants", "admin");
+	}
+	
+	final Map<String, String[]> enums_bad_enumName_null = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" },
+			"null", new String[] { "foo", "bar", "tar" } // null enum-name -- "null" is a special value that leads to a null enum name
+	);
+	
+	final Map<String, String[]> enums_bad_enumName_blank = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" },
+			"  ", new String[] { "foo", "bar", "tar" } // enum name is all spaces
+	);
+	
+	final Map<String, String[]> enums_bad_Elements_empty = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" },
+			"anEnum", new String[] { } // enum elements collection is empty
+	);
+	
+	final Map<String, String[]> enums_bad_enumName_duplicate_exact = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" }
+	);
+	
+	final Map<String, String[]> enums_bad_enumName_duplicate_differentCase = ImmutableMap.of(
+			"authentication-type", new String[] { "simple", "kerberos" },
+			"time-unit", new String[] { "day", "hour", "minute" },
+			"Authentication-Type", new String[] { } // duplicate enum-name different in case
+	);
+	
+	@Test
+	public final void test_isValidEnums_happyPath() {
+		List<RangerEnumDef> input = _utils.createEnumDefs(enums_good);
+		assertTrue(_validator.isValidEnums(input, _failures));
+		assertTrue(_failures.isEmpty());
+	}
+	
+	@Test
+	public final void test_isValidEnums_failures() {
+		// null elements in enum def list are a failure
+		List<RangerEnumDef> input = _utils.createEnumDefs(enums_good);
+		input.add(null);
+		assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForMissingValue(_failures, "enum def");
+		
+		// enum names should be valid
+		input = _utils.createEnumDefs(enums_bad_enumName_null);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForMissingValue(_failures, "enum def name");
+
+		input = _utils.createEnumDefs(enums_bad_enumName_blank);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForMissingValue(_failures, "enum def name");
+		
+		// enum elements collection should not be null or empty
+		input = _utils.createEnumDefs(enums_good);
+		RangerEnumDef anEnumDef = mock(RangerEnumDef.class);
+		when(anEnumDef.getName()).thenReturn("anEnum");
+		when(anEnumDef.getElements()).thenReturn(null);
+		input.add(anEnumDef);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForMissingValue(_failures, "enum values", "anEnum");
+
+		input = _utils.createEnumDefs(enums_bad_Elements_empty);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForMissingValue(_failures, "enum values", "anEnum");
+	
+		// enum names should be distinct -- exact match
+		input = _utils.createEnumDefs(enums_good);
+		// add an element with same name as the first element
+		String name = input.iterator().next().getName();
+		when(anEnumDef.getName()).thenReturn(name);
+		List<RangerEnumElementDef> elementDefs = _utils.createEnumElementDefs(new String[] {"val1", "val2"}); 
+		when(anEnumDef.getElements()).thenReturn(elementDefs);
+		input.add(anEnumDef);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForSemanticError(_failures, "enum def name", name);
+
+		// enum names should be distinct -- case insensitive
+		input = _utils.createEnumDefs(enums_bad_enumName_duplicate_differentCase);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForSemanticError(_failures, "enum def name", "Authentication-Type");
+	
+		// enum default index should be right
+		input = _utils.createEnumDefs(enums_good);
+		// set the index of 1st on to be less than 0
+		when(input.iterator().next().getDefaultIndex()).thenReturn(-1);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForSemanticError(_failures, "enum default index", "authentication-type");
+		// set the index to be more than number of elements
+		when(input.iterator().next().getDefaultIndex()).thenReturn(2);
+		_failures.clear(); assertFalse(_validator.isValidEnums(input, _failures));
+		_utils.checkFailureForSemanticError(_failures, "enum default index", "authentication-type");
+	}
+
+	@Test
+	public final void test_isValidEnumElements_happyPath() {
+		List<RangerEnumElementDef> input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos" });
+		assertTrue(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		assertTrue(_failures.isEmpty());
+	}
+
+	@Test
+	public final void test_isValidEnumElements_failures() {
+		// enum element collection should not have nulls in it
+		List<RangerEnumElementDef> input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos" });
+		input.add(null);
+		assertFalse(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		_utils.checkFailureForMissingValue(_failures, "enum element", "anEnum");
+
+		// element names can't be null/empty
+		input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos", null });
+		_failures.clear(); assertFalse(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		_utils.checkFailureForMissingValue(_failures, "enum element name", "anEnum");
+
+		input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos", "		" }); // two tabs
+		_failures.clear(); assertFalse(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		_utils.checkFailureForMissingValue(_failures, "enum element name", "anEnum");
+		
+		// element names should be distinct - case insensitive
+		input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos", "kerberos" }); // duplicate name - exact match
+		_failures.clear(); assertFalse(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		_utils.checkFailureForSemanticError(_failures, "enum element name", "anEnum");
+		
+		input = _utils.createEnumElementDefs(new String[] { "simple", "kerberos", "kErbErOs" }); // duplicate name - different case
+		_failures.clear(); assertFalse(_validator.isValidEnumElements(input, _failures, "anEnum"));
+		_utils.checkFailureForSemanticError(_failures, "enum element name", "anEnum");
+	}
+	
+	private ValidationTestUtils _utils = new ValidationTestUtils();
+	RangerServiceDef _serviceDef;
+	List<ValidationFailureDetails> _failures;
+	ServiceStore _store;
+	RangerServiceDefValidator _validator;
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerValidator.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerValidator.java b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerValidator.java
index d3ee6d6..7da6672 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerValidator.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerValidator.java
@@ -26,26 +26,32 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 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.RangerEnumDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
 import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.rest.RangerValidator.Action;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.collect.Maps;
+
 public class TestRangerValidator {
 
 	static class RangerValidatorForTest extends RangerValidator {
@@ -238,13 +244,14 @@ public class TestRangerValidator {
 		assertTrue(accessTypes.isEmpty());
 		
 		// access type defs with null empty blank names are skipped, spaces within names are preserved
-		String[] names = new String[] { null, "", "a", "  ", "b ", "		", " c" };
+		String[] names = new String[] { null, "", "a", "  ", "b ", "		", " C", "	D	" };
 		accessTypeDefs.addAll(_utils.createAccessTypeDefs(names));
 		accessTypes = _validator.getAccessTypes(serviceDef);
-		assertEquals(3, accessTypes.size());
+		assertEquals(4, accessTypes.size());
 		assertTrue(accessTypes.contains("a"));
 		assertTrue(accessTypes.contains("b "));
 		assertTrue(accessTypes.contains(" c"));
+		assertTrue(accessTypes.contains("	d	"));
 	}
 	
 	@Test
@@ -270,22 +277,24 @@ public class TestRangerValidator {
 		
 		// access type defs with null empty blank names are skipped, spaces within names are preserved
 		Object[][] data = {
-				{ "a", true }, // all good
-				null,          // this should put a null element in the resource def!
-				{ "b", null }, // mandatory field is null, i.e. false
-				{ "c", false }, // mandatory field false
-				{ "d", true }, // all good
+				{ "a", true },  // all good
+				null,           // this should put a null element in the resource def!
+				{ "b", null },  // mandatory field is null, i.e. false
+				{ "c", false }, // non-mandatory field false - upper case
+				{ "D", true },  // resource specified in upper case
+				{ "E", false }, // all good
 		};
 		resourceDefs.addAll(_utils.createResourceDefs(data));
 		accessTypes = _validator.getMandatoryResourceNames(serviceDef);
 		assertEquals(2, accessTypes.size());
 		assertTrue(accessTypes.contains("a"));
-		assertTrue(accessTypes.contains("d"));
+		assertTrue(accessTypes.contains("d")); // name should come back lower case
 		
 		accessTypes = _validator.getAllResourceNames(serviceDef);
-		assertEquals(4, accessTypes.size());
+		assertEquals(5, accessTypes.size());
 		assertTrue(accessTypes.contains("b"));
 		assertTrue(accessTypes.contains("c"));
+		assertTrue(accessTypes.contains("e"));
 	}
 
 	@Test
@@ -327,6 +336,137 @@ public class TestRangerValidator {
 		assertEquals("regex3", regExMap.get("f"));
 	}
 
+	@Test
+	public void test_getPolicyResources() {
+		
+		Set<String> result;
+		RangerPolicy policy = null;
+		// null policy
+		result = _validator.getPolicyResources(null);
+		assertTrue(result != null);
+		assertTrue(result.isEmpty());
+		// null resource map
+		policy = mock(RangerPolicy.class);
+		when(policy.getResources()).thenReturn(null);
+		result = _validator.getPolicyResources(null);
+		assertTrue(result != null);
+		assertTrue(result.isEmpty());
+		// empty resource map
+		Map<String, RangerPolicyResource> input = Maps.newHashMap();
+		when(policy.getResources()).thenReturn(input);
+		result = _validator.getPolicyResources(policy);
+		assertTrue(result != null);
+		assertTrue(result.isEmpty());
+		// known resource map
+		input.put("r1", mock(RangerPolicyResource.class));
+		input.put("R2", mock(RangerPolicyResource.class));
+		result = _validator.getPolicyResources(policy);
+		assertEquals(2, result.size());
+		assertTrue("r1", result.contains("r1"));
+		assertTrue("R2", result.contains("r2")); // result should lowercase the resource-names
+	}
+
+	@Test
+	public void test_getIsAuditEnabled() {
+		// null policy
+		RangerPolicy policy = null;
+		boolean result = _validator.getIsAuditEnabled(policy);
+		assertFalse(result);
+		// null isAuditEnabled Boolean is supposed to be TRUE!!
+		policy = mock(RangerPolicy.class);
+		when(policy.getIsAuditEnabled()).thenReturn(null);
+		result = _validator.getIsAuditEnabled(policy);
+		assertTrue(result);
+		// non-null value
+		when(policy.getIsAuditEnabled()).thenReturn(Boolean.FALSE);
+		result = _validator.getIsAuditEnabled(policy);
+		assertFalse(result);
+
+		when(policy.getIsAuditEnabled()).thenReturn(Boolean.TRUE);
+		result = _validator.getIsAuditEnabled(policy);
+		assertTrue(result);
+	}
+
+	@Test
+	public void test_getPolicies() throws Exception {
+
+		// returns null when store returns null
+		String policyName = "aPolicy";
+		String serviceName = "aService";
+		SearchFilter filter = new SearchFilter();
+		filter.setParam(SearchFilter.POLICY_NAME, policyName);
+		filter.setParam(SearchFilter.SERVICE_NAME, serviceName);
+		
+		when(_store.getPolicies(filter)).thenReturn(null);
+		List<RangerPolicy> result = _validator.getPolicies(policyName, serviceName);
+		// validate store is queried with both parameters
+		verify(_store).getPolicies(filter);
+		assertNull(result);
+
+		// returns null if store throws an exception
+		when(_store.getPolicies(filter)).thenThrow(new Exception());
+		result = _validator.getPolicies(policyName, serviceName);
+		assertNull(result);
+	}
+	
+	@Test
+	public void test_getServiceDef_byId() throws Exception {
+		// if service store returns null or throws an exception then service is deemed invalid
+		when(_store.getServiceDef(1L)).thenReturn(null);
+		when(_store.getServiceDef(2L)).thenThrow(new Exception());
+		RangerServiceDef serviceDef = mock(RangerServiceDef.class);
+		when(_store.getServiceDef(3L)).thenReturn(serviceDef);
+		
+		assertNull(_validator.getServiceDef(1L));
+		assertNull(_validator.getServiceDef(2L));
+		assertTrue(_validator.getServiceDef(3L) != null);
+	}
+
+	@Test
+	public void test_getEnumDefaultIndex() {
+		RangerEnumDef enumDef = mock(RangerEnumDef.class);
+		assertEquals(-1, _validator.getEnumDefaultIndex(null));
+		when(enumDef.getDefaultIndex()).thenReturn(null);
+		assertEquals(0, _validator.getEnumDefaultIndex(enumDef));
+		when(enumDef.getDefaultIndex()).thenReturn(-5);
+		assertEquals(-5, _validator.getEnumDefaultIndex(enumDef));
+	}
+	
+	@Test
+	public void test_getImpliedGrants() {
+		
+		// passing in null gets back a null
+		Collection<String> result = _validator.getImpliedGrants(null);
+		assertNull(result);
+		
+		// null or empty implied grant collection gets back an empty collection
+		RangerAccessTypeDef accessTypeDef = mock(RangerAccessTypeDef.class);
+		when(accessTypeDef.getImpliedGrants()).thenReturn(null);
+		result = _validator.getImpliedGrants(accessTypeDef);
+		assertTrue(result.isEmpty());
+		
+		List<String> impliedGrants = new ArrayList<String>();
+		when(accessTypeDef.getImpliedGrants()).thenReturn(impliedGrants);
+		result = _validator.getImpliedGrants(accessTypeDef);
+		assertTrue(result.isEmpty());
+
+		// null/empty values come back as is
+		impliedGrants = Arrays.asList(new String[] { null, "", " ", "		" });
+		when(accessTypeDef.getImpliedGrants()).thenReturn(impliedGrants);
+		result = _validator.getImpliedGrants(accessTypeDef);
+		assertEquals(4, result.size());
+		
+		// non-empty values get lower cased
+		impliedGrants = Arrays.asList(new String[] { "a", "B", "C	", " d " });
+		when(accessTypeDef.getImpliedGrants()).thenReturn(impliedGrants);
+		result = _validator.getImpliedGrants(accessTypeDef);
+		assertEquals(4, result.size());
+		assertTrue(result.contains("a"));
+		assertTrue(result.contains("b"));
+		assertTrue(result.contains("c	"));
+		assertTrue(result.contains(" d "));
+	}
+	
 	private RangerValidatorForTest _validator;
 	private ServiceStore _store;
 	private ValidationTestUtils _utils = new ValidationTestUtils();

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java
index da15ffa..d112b83 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java
@@ -37,6 +37,7 @@ import org.apache.ranger.biz.ServiceDBStore;
 import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.rest.RangerValidator.Action;
 import org.junit.Before;
 import org.junit.Test;
@@ -51,6 +52,7 @@ public class TestServiceRESTForValidation {
 		// inject out store in it
 		_store = mock(ServiceDBStore.class);
 		_serviceRest.svcStore = _store;
+		
 		// and our validator factory
 		_factory = mock(RangerValidatorFactory.class);
 		_serviceValidator = mock(RangerServiceValidator.class);
@@ -58,6 +60,9 @@ public class TestServiceRESTForValidation {
 		_policyValidator = mock(RangerPolicyValidator.class);
 		when(_factory.getPolicyValidator(_store)).thenReturn(_policyValidator);
 		_serviceRest.validatorFactory = _factory;
+		_serviceDefValidator = mock(RangerServiceDefValidator.class);
+		when(_factory.getServiceDefValidator(_store)).thenReturn(_serviceDefValidator);
+
 		// and other things that are needed for service rest to work correctly
 		_restErrorUtil = mock(RESTErrorUtil.class);
 		WebApplicationException webApplicationException = new WebApplicationException();
@@ -85,7 +90,7 @@ public class TestServiceRESTForValidation {
 			// 
 			_serviceRest.updateService(_service);
 			verify(_serviceValidator).validate(_service, Action.UPDATE);
-
+	
 			_serviceRest.deleteService(3L);
 			verify(_serviceValidator).validate(3L, Action.DELETE);
 		} catch (Throwable t) {
@@ -93,7 +98,7 @@ public class TestServiceRESTForValidation {
 			fail("Unexpected exception thrown!");
 		}
 	}
-
+	
 	@Test
 	public final void testService_storeFailure() throws Exception {
 		/*
@@ -283,14 +288,120 @@ public class TestServiceRESTForValidation {
 			fail("Unexpected exception!");
 		}
 	}
+
+	@Test
+	public final void testServiceDef_happyPath() throws Exception {
+		/*
+		 * Creation should succeed if neither validator nor dbstore throw exception.
+		 * - by default mocks return null for unspecified methods, so no additional mocking needed.
+		 * - We just assert that validator is called with right set of arguments.
+		 * - db store would also have been excercised but that is not the focus of this test, so we don't assert about it!!
+		 */
+		try {
+			_serviceRest.createServiceDef(_serviceDef);
+			verify(_serviceDefValidator).validate(_serviceDef, Action.CREATE);
+			// 
+			_serviceRest.updateServiceDef(_serviceDef);
+			verify(_serviceDefValidator).validate(_serviceDef, Action.UPDATE);
+
+			_serviceRest.deleteServiceDef(3L);
+			verify(_serviceDefValidator).validate(3L, Action.DELETE);
+		} catch (Throwable t) {
+			t.printStackTrace();
+			fail("Unexpected exception thrown!");
+		}
+	}
 	
-	RangerValidatorFactory _factory;
-	RangerServiceValidator _serviceValidator;
-	RangerPolicyValidator _policyValidator;
-	ServiceDBStore _store;
-	ServiceREST _serviceRest;
-	RangerService _service;
-	RangerPolicy _policy;
-	Exception _exception;
-	RESTErrorUtil _restErrorUtil;
+	@Test
+	public void testServiveDef_validatorFailure() throws Exception {
+		
+		doThrow(_exception).when(_serviceDefValidator).validate(_serviceDef, Action.CREATE);
+		try {
+			_serviceRest.createServiceDef(_serviceDef);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException t) {
+			verify(_serviceDefValidator).validate(_serviceDef, Action.CREATE);
+			verify(_store, never()).createServiceDef(_serviceDef);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+
+		doThrow(_exception).when(_serviceDefValidator).validate(_serviceDef, Action.UPDATE);
+		try {
+			_serviceRest.updateServiceDef(_serviceDef);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException t) {
+			verify(_serviceDefValidator).validate(_serviceDef, Action.UPDATE);
+			verify(_store, never()).updateServiceDef(_serviceDef);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+
+		doThrow(_exception).when(_serviceDefValidator).validate(4L, Action.DELETE);
+		try {
+			_serviceRest.deleteServiceDef(4L);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException t) {
+			verify(_serviceDefValidator).validate(4L, Action.DELETE);
+			verify(_store, never()).deleteServiceDef(4L);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+	}
+	
+	@Test
+	public void testServiceDef_storeFailure() throws Exception {
+		doThrow(_exception).when(_store).createServiceDef(_serviceDef);
+		try {
+			_serviceRest.createServiceDef(_serviceDef);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException e) {
+			verify(_serviceDefValidator).validate(_serviceDef, Action.CREATE);
+			verify(_store).createServiceDef(_serviceDef);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+		
+		doThrow(_exception).when(_store).updateServiceDef(_serviceDef);
+		try {
+			_serviceRest.updateServiceDef(_serviceDef);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException e) {
+			verify(_serviceDefValidator).validate(_serviceDef, Action.UPDATE);
+			verify(_store).updateServiceDef(_serviceDef);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+		
+		doThrow(_exception).when(_store).deleteServiceDef(5L);
+		try {
+			_serviceRest.deleteServiceDef(5L);
+			fail("Should have thrown exception!");
+		} catch (WebApplicationException e) {
+			verify(_serviceDefValidator).validate(5L, Action.DELETE);
+			verify(_store).deleteServiceDef(5L);
+		} catch (Throwable t) {
+			LOG.debug(t);
+			fail("Unexpected exception!");
+		}
+	}
+
+	private RangerValidatorFactory _factory;
+	private RangerServiceValidator _serviceValidator;
+	private RangerPolicyValidator _policyValidator;
+	private RangerServiceDefValidator _serviceDefValidator;
+
+	private ServiceDBStore _store;
+	private ServiceREST _serviceRest;
+	private Exception _exception;
+	private RESTErrorUtil _restErrorUtil;
+
+	private RangerService _service;
+	private RangerPolicy _policy;
+	private RangerServiceDef _serviceDef;
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6e9f2a3b/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java b/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java
index b734763..6c71502 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java
@@ -37,6 +37,8 @@ import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerEnumElementDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
 
@@ -119,6 +121,30 @@ public class ValidationTestUtils {
 		return defs;
 	}
 
+
+	List<RangerAccessTypeDef> createAccessTypeDefs(Object[][] data) {
+		if (data == null) {
+			return null;
+		}
+		List<RangerAccessTypeDef> result = new ArrayList<RangerAccessTypeDef>();
+		if (data.length == 0) {
+			return result;
+		}
+		for (Object[] entry : data) {
+			String accessType = (String)entry[0];
+			String[] impliedAccessArray = (String[])entry[1];
+			List<String> impliedAccesses = null;
+			if (impliedAccessArray != null) {
+				impliedAccesses = Arrays.asList(impliedAccessArray);
+			}
+			RangerAccessTypeDef aTypeDef = mock(RangerAccessTypeDef.class);
+			when(aTypeDef.getName()).thenReturn(accessType);
+			when(aTypeDef.getImpliedGrants()).thenReturn(impliedAccesses);
+			result.add(aTypeDef);
+		}
+		return result;
+	}
+
 	RangerServiceDef createServiceDefWithAccessTypes(String[] accesses) {
 		RangerServiceDef serviceDef = mock(RangerServiceDef.class);
 		List<RangerAccessTypeDef> accessTypeDefs = new ArrayList<RangerServiceDef.RangerAccessTypeDef>();
@@ -249,4 +275,38 @@ public class ValidationTestUtils {
 		}
 		return resourceMap;
 	}
+
+	List<RangerEnumElementDef> createEnumElementDefs(String[] input) {
+		if (input == null) {
+			return null;
+		}
+		List<RangerEnumElementDef> output = new ArrayList<RangerEnumElementDef>();
+		for (String elementName : input) {
+			RangerEnumElementDef aDef = mock(RangerEnumElementDef.class);
+			when(aDef.getName()).thenReturn(elementName);
+			output.add(aDef);
+		}
+		return output;
+	}
+
+	List<RangerEnumDef> createEnumDefs(Map<String, String[]> input) {
+		if (input == null) {
+			return null;
+		}
+		List<RangerEnumDef> defs = new ArrayList<RangerEnumDef>();
+		for (Map.Entry<String, String[]> entry : input.entrySet()) {
+			RangerEnumDef enumDef = mock(RangerEnumDef.class);
+			String enumName = entry.getKey();
+			if ("null".equals(enumName)) { // special handling to process null hint in enum-name
+				enumName = null;
+			}
+			when(enumDef.getName()).thenReturn(enumName);
+			List<RangerEnumElementDef> elements = createEnumElementDefs(entry.getValue());
+			when(enumDef.getElements()).thenReturn(elements);
+			// by default set default index to last element
+			when(enumDef.getDefaultIndex()).thenReturn(elements.size() - 1);
+			defs.add(enumDef);
+		}
+		return defs;
+	}
 }