Repository: incubator-ranger
Updated Branches:
  refs/heads/master 054a973df -> d69fc28d2


RANGER-278 Add validation for service create/update/delete operations

Signed-off-by: Madhan Neethiraj <[email protected]>


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

Branch: refs/heads/master
Commit: d69fc28d2fbd5efe3741819cc8010e56ed5b9fa8
Parents: 054a973
Author: Alok Lal <[email protected]>
Authored: Tue Feb 24 13:22:15 2015 -0800
Committer: Madhan Neethiraj <[email protected]>
Committed: Tue Mar 3 14:40:23 2015 -0800

----------------------------------------------------------------------
 pom.xml                                         |  30 +--
 ranger-util/pom.xml                             |   1 -
 security-admin/pom.xml                          |   1 -
 .../org/apache/ranger/biz/ServiceDBStore.java   |  19 ++
 .../ranger/rest/RangerServiceValidator.java     | 188 +++++++++++++
 .../org/apache/ranger/rest/RangerValidator.java | 162 ++++++++++++
 .../ranger/rest/RangerValidatorFactory.java     |  29 ++
 .../org/apache/ranger/rest/ServiceREST.java     |  12 +
 .../ranger/rest/ValidationFailureDetails.java   |  91 +++++++
 .../rest/ValidationFailureDetailsBuilder.java   |  64 +++++
 .../ranger/rest/TestRangerServiceValidator.java | 262 +++++++++++++++++++
 .../rest/TestServiceRESTForValidation.java      | 129 +++++++++
 .../ranger/rest/TestServiceValidator.java       | 202 ++++++++++++++
 .../apache/ranger/rest/ValidationTestUtils.java |  57 ++++
 .../process/LdapUserGroupBuilder.java           |   1 -
 15 files changed, 1217 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b2a955d..93cba79 100644
--- a/pom.xml
+++ b/pom.xml
@@ -166,6 +166,7 @@
                <velocity.version>1.7</velocity.version>
                <powermock.version>1.5.6</powermock.version>
                <aspectj.version>1.8.2</aspectj.version>
+               <findbugs.plugin.version>3.0.0</findbugs.plugin.version>
                <distMgmtStagingId>apache.staging.https</distMgmtStagingId>
        <distMgmtStagingName>Apache Release Distribution 
Repository</distMgmtStagingName>
        
<distMgmtStagingUrl>https://repository.apache.org/service/local/staging/deploy/maven2</distMgmtStagingUrl>
@@ -389,34 +390,6 @@
         <artifactId>maven-release-plugin</artifactId>
         <version>2.5</version>
       </plugin>
-           <!--This plugin's configuration is used to store Eclipse 
-            m2e settings only. It has no influence on the Maven build itself. 
-        -->
-        <plugin>
-            <groupId>org.eclipse.m2e</groupId>
-            <artifactId>lifecycle-mapping</artifactId>
-            <version>1.0.0</version>
-            <configuration>
-                <lifecycleMappingMetadata>
-                    <pluginExecutions>
-                        <pluginExecution>
-                            <pluginExecutionFilter>
-                                <groupId>org.apache.maven.plugins</groupId>
-                                <artifactId>maven-antrun-plugin</artifactId>
-                                <versionRange>[1.0,)</versionRange>
-                                <goals>
-                                    <goal>run</goal>
-                                </goals>
-                            </pluginExecutionFilter>
-                            <action>
-                                <execute />
-                            </action>
-                        </pluginExecution>
-                    </pluginExecutions>
-                </lifecycleMappingMetadata>
-            </configuration>
-        </plugin>
-       
     </plugins>
     
     </pluginManagement>
@@ -496,6 +469,7 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
+        <version>${findbugs.plugin.version}</version>
 <!--
         <configuration>
           <excludeFilterFile>${basedir}/dev-support/findbugsExcludeFile.xml

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/ranger-util/pom.xml
----------------------------------------------------------------------
diff --git a/ranger-util/pom.xml b/ranger-util/pom.xml
index 047008a..fabbf2c 100644
--- a/ranger-util/pom.xml
+++ b/ranger-util/pom.xml
@@ -26,7 +26,6 @@
                <version>0.4.0</version>
        </parent>
        <artifactId>ranger-util</artifactId>
-       <version>0.4.0</version>
        <name>ranger-util</name>
        <description>Common Utilities of Ranger</description>
        <dependencies>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/pom.xml
----------------------------------------------------------------------
diff --git a/security-admin/pom.xml b/security-admin/pom.xml
index 6d313b6..ce754ab 100644
--- a/security-admin/pom.xml
+++ b/security-admin/pom.xml
@@ -18,7 +18,6 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>security-admin-web</artifactId>
-  <version>0.4.0</version>
   <name>Security Admin Web Application</name>
   <description>security-admin-tool java web application</description>
   <packaging>war</packaging>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
----------------------------------------------------------------------
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 0cb1707..9c59933 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
@@ -1,3 +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.
+ */
+
 package org.apache.ranger.biz;
 
 import java.util.ArrayList;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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
new file mode 100644
index 0000000..08184c7
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/rest/RangerServiceValidator.java
@@ -0,0 +1,188 @@
+/*
+ * 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.rest;
+
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+
+import com.google.common.collect.Sets;
+
+public class RangerServiceValidator extends RangerValidator {
+
+       private static final Log LOG = 
LogFactory.getLog(RangerServiceValidator.class);
+
+       public RangerServiceValidator(ServiceStore store, Action action) {
+               super(store, action);
+       }
+
+       public void validate(RangerService service) throws Exception {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerValidator.validate(" + service + 
")");
+               }
+
+               if (isValid(service)) {
+                       if(LOG.isDebugEnabled()) {
+                               LOG.debug("<== RangerValidator.validate(" + 
service + "): valid");
+                       }
+               } else {
+                       String message = getFailureMessage();
+                       LOG.debug("<== RangerValidator.validate(" + service + 
"): invalid, reason[" + message + "]");
+                       throw new Exception(message);
+               }
+       }
+       
+       public void validate(long id) throws Exception {
+               if (isValid(id)) {
+                       if(LOG.isDebugEnabled()) {
+                               LOG.debug("<== RangerValidator.validate(" + id 
+ "): valid");
+                       }
+               } else {
+                       String message = getFailureMessage();
+                       LOG.debug("<== RangerValidator.validate(" + id + "): 
invalid, reason[" + message + "]");
+                       throw new Exception(message);
+               }
+       }
+       
+       boolean isValid(Long id) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerServiceValidator.isValid(" + id + 
")");
+               }
+
+               if (_action != Action.DELETE) {
+                       addFailure(new ValidationFailureDetailsBuilder()
+                               .isAnInternalError()
+                               .becauseOf("isValid(Long) is only supported for 
DELETE")
+                               .build());
+               } else if (id == null) {
+                       addFailure(new ValidationFailureDetailsBuilder()
+                               .field("id")
+                               .isMissing()
+                               .build());
+               } else {
+                       boolean found = false;
+                       try {
+                               if (_store.getService(id) != null) {
+                                       found = true;
+                               }
+                       } catch (Exception e) {
+                               LOG.debug("Encountred exception while 
retrieving service from service store!", e);
+                       }
+                       if (!found) {
+                               addFailure(new ValidationFailureDetailsBuilder()
+                                       .field("id")
+                                       .isSemanticallyIncorrect()
+                                       .becauseOf("no service found for id[" + 
id + "]")
+                                       .build());
+                       }
+               }
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerServiceValidator.isValid(" + id + 
"): " + _valid);
+               }
+               return _valid;
+       }
+       
+       boolean isValid(RangerService service) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerServiceValidator.isValid(" + 
service + ")");
+               }
+               
+               if (service == null) {
+                       String message = "service object passed in was null";
+                       LOG.debug(message);
+                       addFailure(new ValidationFailureDetailsBuilder()
+                               .field("service")
+                               .isMissing()
+                               .becauseOf(message)
+                               .build());
+               } else {
+                       String name = service.getName();
+                       String type = service.getType();
+                       boolean nameSpecified = StringUtils.isNotBlank(name);
+                       boolean typeSpecified = StringUtils.isNotBlank(type);
+                       RangerService existingService = null;
+                       RangerServiceDef serviceDef = null;
+                       if (!nameSpecified) {
+                               String message = "service name was 
null/empty/blank"; 
+                               LOG.debug(message);
+                               addFailure(new ValidationFailureDetailsBuilder()
+                                       .field("name")
+                                       .isMissing()
+                                       .becauseOf(message)
+                                       .build());
+                       } else {
+                               existingService = getService(name);
+                               if (existingService != null && _action == 
Action.CREATE) {
+                                       addFailure(new 
ValidationFailureDetailsBuilder()
+                                               .field("name")
+                                               .isSemanticallyIncorrect()
+                                               .becauseOf("service with the 
same name already exists")
+                                               .build());
+                               } else if (existingService == null && _action 
== Action.UPDATE) {
+                                       addFailure(new 
ValidationFailureDetailsBuilder()
+                                               .field("name")
+                                               .isSemanticallyIncorrect()
+                                               .becauseOf("service with the 
same name doesn't exist")
+                                               .build());
+                               }
+                       }
+                       if (!typeSpecified) {
+                               addFailure(new ValidationFailureDetailsBuilder()
+                                       .field("type")
+                                       .isMissing()
+                                       .becauseOf("service def was 
null/empty/blank")
+                                       .build());
+                       } else {
+                               serviceDef = getServiceDef(type);
+                               if (serviceDef == null) {
+                                       addFailure(new 
ValidationFailureDetailsBuilder()
+                                               .field("type")
+                                               .isSemanticallyIncorrect()
+                                               .becauseOf("service def not 
found")
+                                               .build());
+                               }
+                       }
+                       if (nameSpecified && serviceDef != null) {
+                               Set<String> reqiredParameters = 
getRequiredParameters(serviceDef);
+                               Set<String> inputParameters = 
getServiceConfigParameters(service);
+                               Set<String> missingParameters = 
Sets.difference(reqiredParameters, inputParameters);
+                               if (!missingParameters.isEmpty()) {
+                                       addFailure(new 
ValidationFailureDetailsBuilder()
+                                               .field("configuration")
+                                               
.subField(missingParameters.iterator().next()) // we return any one parameter!
+                                               .isMissing()
+                                               .becauseOf("required 
configuration parameter is missing")
+                                               .build());
+                               }
+                       }
+               }
+               
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerServiceValidator.isValid(" + 
service + "): " + _valid);
+               }
+               return _valid;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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
new file mode 100644
index 0000000..3f25266
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidator.java
@@ -0,0 +1,162 @@
+/*
+ * 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.rest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+
+public abstract class RangerValidator {
+       
+       private static final Log LOG = LogFactory.getLog(RangerValidator.class);
+
+       ServiceStore _store;
+       boolean _valid = true;
+       List<ValidationFailureDetails> _failures;
+       Action _action;
+
+       public enum Action {
+               CREATE, UPDATE, DELETE;
+       };
+       
+       protected RangerValidator(ServiceStore store, Action action) {
+               if (store == null) {
+                       throw new IllegalArgumentException("ServiceValidator(): 
store is null!");
+               }
+               _store = store;
+               if (action == null) {
+                       throw new IllegalArgumentException("ServiceValidator(): 
action is null!");
+               }
+               _action = action;
+       }
+
+       protected List<ValidationFailureDetails> getFailures() {
+               if (_valid) {
+                       LOG.warn("getFailureDetails: called while _valid == 
true");
+               }
+               return _failures;
+       }
+       
+       String getFailureMessage() {
+               if (_valid) {
+                       LOG.warn("getFailureDetails: called while validator is 
true!");
+               }
+               if (_failures == null) {
+                       LOG.warn("getFailureDetails: called while list of 
failures is null!");
+                       return null;
+               }
+               StringBuilder builder = new StringBuilder();
+               for (ValidationFailureDetails aFailure : _failures) {
+                       builder.append(aFailure.toString());
+                       builder.append(";");
+               }
+               return builder.toString();
+       }
+
+       void addFailure(ValidationFailureDetails aFailure) {
+               if (_failures == null) {
+                       _failures = new ArrayList<ValidationFailureDetails>();
+               }
+               _failures.add(aFailure);
+               _valid = false;
+       }
+       
+       Set<String> getServiceConfigParameters(RangerService service) {
+               if (service == null || service.getConfigs() == null) {
+                       return new HashSet<String>();
+               } else {
+                       return service.getConfigs().keySet();
+               }
+       }
+
+       Set<String> getRequiredParameters(RangerServiceDef serviceDef) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerServiceValidator.getRequiredParameters(" + serviceDef + ")");
+               }
+
+               Set<String> result;
+               if (serviceDef == null) {
+                       result = Collections.emptySet();
+               } else {
+                       List<RangerServiceConfigDef> configs = 
serviceDef.getConfigs();
+                       if (CollectionUtils.isEmpty(configs)) {
+                               result = Collections.emptySet();
+                       } else {
+                               result = new HashSet<String>(configs.size()); 
// at worse all of the config items are required!
+                               for (RangerServiceConfigDef configDef : 
configs) {
+                                       if (configDef.getMandatory()) {
+                                               result.add(configDef.getName());
+                                       }
+                               }
+                       }
+               }
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerServiceValidator.getRequiredParameters(" + serviceDef + "): " + result);
+               }
+               return result;
+       }
+
+       RangerServiceDef getServiceDef(String type) {
+               
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerServiceValidator.getServiceDef(" + 
type + ")");
+               }
+               RangerServiceDef result = null;
+               try {
+                       result = _store.getServiceDefByName(type);
+               } catch (Exception e) {
+                       LOG.debug("Encountred exception while retrieving 
service definition from service store!", e);
+               }
+               
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerServiceValidator.getServiceDef(" + 
type + "): " + result);
+               }
+               return result;
+       }
+
+       RangerService getService(String name) {
+               
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerServiceValidator.getService(" + 
name + ")");
+               }
+               RangerService result = null;
+               try {
+                       result = _store.getServiceByName(name);
+               } catch (Exception e) {
+                       LOG.debug("Encountred exception while retrieving 
service from service store!", e);
+               }
+               
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerServiceValidator.getService(" + 
name + "): " + result);
+               }
+               return result;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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
new file mode 100644
index 0000000..6c75a2f
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/rest/RangerValidatorFactory.java
@@ -0,0 +1,29 @@
+/*
+ * 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.rest;
+
+import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.rest.RangerValidator.Action;
+
+public class RangerValidatorFactory {
+       RangerServiceValidator getServiceValidator(ServiceStore store, Action 
action) {
+               return new RangerServiceValidator(store, action);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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 b90a3df..ab09bf6 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
@@ -59,6 +59,7 @@ import org.apache.ranger.plugin.service.ResourceLookupContext;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.plugin.util.ServicePolicies;
+import org.apache.ranger.rest.RangerValidator.Action;
 import org.apache.ranger.view.VXResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
@@ -92,6 +93,10 @@ public class ServiceREST {
 
        @Autowired
        ServiceDBStore svcStore;
+       
+       // this indirection for validation via a factory exists only for 
testability
+       // TODO move the instantiation to DI framework?
+       RangerValidatorFactory validatorFactory = new RangerValidatorFactory(); 
 
        public ServiceREST() {
        }
@@ -269,6 +274,9 @@ public class ServiceREST {
                RangerService ret = null;
 
                try {
+                       RangerServiceValidator validator = 
validatorFactory.getServiceValidator(svcStore, Action.CREATE);
+                       validator.validate(service);
+                       
                        ret = svcStore.createService(service);
                } catch(Exception excp) {
                        LOG.error("createService(" + service + ") failed", 
excp);
@@ -295,6 +303,8 @@ public class ServiceREST {
                RangerService ret = null;
 
                try {
+                       RangerServiceValidator validator = 
validatorFactory.getServiceValidator(svcStore, Action.UPDATE);
+                       validator.validate(service);
                        ret = svcStore.updateService(service);
                } catch(Exception excp) {
                        LOG.error("updateService(" + service + ") failed", 
excp);
@@ -319,6 +329,8 @@ public class ServiceREST {
                }
 
                try {
+                       RangerServiceValidator validator = 
validatorFactory.getServiceValidator(svcStore, Action.DELETE);
+                       validator.validate(id);
                        svcStore.deleteService(id);
                } catch(Exception excp) {
                        LOG.error("deleteService(" + id + ") failed", excp);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetails.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetails.java
 
b/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetails.java
new file mode 100644
index 0000000..8ceeba1
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetails.java
@@ -0,0 +1,91 @@
+/*
+ * 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.rest;
+
+import java.util.Objects;
+
+public class ValidationFailureDetails {
+
+       final String _fieldName;
+       final String _subFieldName;
+       final boolean _missing;
+       final boolean _semanticError;
+       final boolean _internalError;
+       final String _reason;
+       
+       public ValidationFailureDetails(String fieldName, String subFieldName, 
boolean missing, boolean semanticError, boolean internalError, String reason) {
+               _missing = missing;
+               _semanticError = semanticError;
+               _internalError = internalError;
+               _fieldName = fieldName;
+               _subFieldName = subFieldName;
+               _reason = reason;
+       }
+
+       public String getFieldName() {
+               return _fieldName;
+       }
+
+       public boolean isMissingRequiredValue() {
+               return _missing;
+       }
+
+       public boolean isSemanticallyIncorrect() {
+               return _semanticError;
+       }
+       
+       String getType() {
+               if (_missing) return "missing";
+               if (_semanticError) return "semantically incorrect";
+               if (_internalError) return "internal error";
+               return "";
+       }
+
+       public String getSubFieldName() {
+               return _subFieldName;
+       }
+       
+       @Override
+       public String toString() {
+               return String.format("Field[%s]%s is %s: reason[%s]", 
+                               _fieldName, 
+                               _subFieldName == null ? "" : ", subField[" + 
_subFieldName + "]",
+                               getType(), _reason);
+       }
+       
+       @Override
+       public int hashCode() {
+               return Objects.hash(_fieldName, _subFieldName, _missing, 
_semanticError, _internalError, _reason);
+       }
+       
+       @Override
+       public boolean equals(Object obj) {
+               if (obj == null || !(obj instanceof ValidationFailureDetails)) {
+                       return false;
+               }
+               ValidationFailureDetails that = (ValidationFailureDetails)obj;
+               return Objects.equals(_fieldName, that._fieldName) && 
+                               Objects.equals(_subFieldName, 
that._subFieldName) && 
+                               Objects.equals(_reason, that._reason) && 
+                               _internalError == that._internalError &&
+                               _missing == that._missing &&
+                               _semanticError == that._semanticError;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetailsBuilder.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetailsBuilder.java
 
b/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetailsBuilder.java
new file mode 100644
index 0000000..b85215d
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/rest/ValidationFailureDetailsBuilder.java
@@ -0,0 +1,64 @@
+/*
+ * 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.rest;
+
+public class ValidationFailureDetailsBuilder {
+       private String _fieldName;
+       private boolean _missing;
+       private boolean _semanticError;
+       private String _reason;
+       private String _subFieldName;
+       private boolean _internalError;
+       
+       ValidationFailureDetailsBuilder becauseOf(String aReason) {
+               _reason = aReason;
+               return this;
+       }
+       
+       ValidationFailureDetailsBuilder isMissing() {
+               _missing = true;
+               return this;
+       }
+       
+       ValidationFailureDetailsBuilder isSemanticallyIncorrect() {
+               _semanticError = true;
+               return this;
+       }
+       
+       ValidationFailureDetailsBuilder field(String fieldName) {
+               _fieldName = fieldName;
+               return this;
+       }
+       
+       ValidationFailureDetails build() {
+               return new ValidationFailureDetails(_fieldName, _subFieldName, 
_missing, _semanticError, _internalError, _reason);
+       }
+
+       ValidationFailureDetailsBuilder subField(String missingParameter) {
+               _subFieldName = missingParameter;
+               return this;
+       }
+
+       ValidationFailureDetailsBuilder isAnInternalError() {
+               _internalError = true;
+               return this;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceValidator.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceValidator.java
 
b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceValidator.java
new file mode 100644
index 0000000..3bbb123
--- /dev/null
+++ 
b/security-admin/src/test/java/org/apache/ranger/rest/TestRangerServiceValidator.java
@@ -0,0 +1,262 @@
+/*
+ * 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.rest;
+
+import static org.junit.Assert.assertFalse;
+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 java.util.List;
+import java.util.Map;
+
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.rest.RangerValidator.Action;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestRangerServiceValidator {
+       
+       final Action[] cud = new Action[] { Action.CREATE, Action.UPDATE, 
Action.DELETE };
+       final Action[] cu = new Action[] { Action.CREATE, Action.UPDATE };
+       final Action[] ud = new Action[] { Action.UPDATE, Action.DELETE };
+
+       @Before
+       public void before() {
+               _store = mock(ServiceStore.class);
+               _action = Action.CREATE; // by default we set action to create
+               _validator = new RangerServiceValidator(_store, _action);
+       }
+
+       @Test
+       public void testIsValid_failures() throws Exception {
+               RangerService service = mock(RangerService.class);
+               List<ValidationFailureDetails> failures;
+               // create/update/delete: null, empty of blank name renders a 
service invalid
+               for (Action action : cud) {
+                       _validator = new RangerServiceValidator(_store, action);
+                       when(service.getName()).thenReturn(null);
+                       assertFalse(_validator.isValid(service));
+                       // let's verify the sort of error information that is 
returned (for one of these)
+                       failures = _validator.getFailures();
+                       // assert that among the failure reason is one about 
field name being missing.
+                       boolean found = false;
+                       for (ValidationFailureDetails f : failures) {
+                               if ("name".equals(f.getFieldName()) && 
+                                               f._internalError == false && 
+                                               f._missing == true &&
+                                               f._semanticError == false) {
+                                       found = true;
+                               }
+                       }
+                       assertTrue("Matching failure located", found);
+                       // let's assert behavior for other flavors of this 
condition, too.
+                       when(service.getName()).thenReturn("");
+                       assertFalse(_validator.isValid(service));
+                       when(service.getName()).thenReturn("  "); // spaces
+                       assertFalse(_validator.isValid(service));
+               }
+               
+               // Create/update: null, empty or blank type is also invalid
+               for (Action action : cu) {
+                       _validator = new RangerServiceValidator(_store, action);
+                       when(service.getName()).thenReturn("aName");
+                       when(service.getType()).thenReturn(null);
+                       assertFalse(_validator.isValid(service));
+                       when(service.getType()).thenReturn("");
+                       assertFalse(_validator.isValid(service));
+                       when(service.getType()).thenReturn("    "); // a tab
+                       assertFalse(_validator.isValid(service));
+                       // let's verify the error information returned (for the 
last scenario)
+                       failures = _validator.getFailures();
+                       boolean found = false;
+                       for (ValidationFailureDetails f : failures) {
+                               if ("type".equals(f._fieldName) && 
+                                               f._missing == true && 
+                                               f._semanticError == false) {
+                                       found = true;
+                               }
+                       }
+                       assertTrue("Matching failure located", found);
+               }
+
+               // Create/update: if non-empty, the type should also exist!
+               for (Action action : cu) {
+                       _validator = new RangerServiceValidator(_store, action);
+                       when(service.getName()).thenReturn("aName");
+                       when(service.getType()).thenReturn("aType");
+                       
when(_store.getServiceDefByName("aType")).thenReturn(null);
+                       assertFalse(_validator.isValid(service));
+                       // let's verify the error information returned (for the 
last scenario)
+                       failures = _validator.getFailures();
+                       boolean found = false;
+                       for (ValidationFailureDetails f : failures) {
+                               if ("type".equals(f._fieldName) && 
+                                               f._missing == false && 
+                                               f._semanticError == true) {
+                                       found = true;
+                               }
+                       }
+                       assertTrue("Matching failure located", found);
+               }
+               
+               // Create: if service already exists then that such a service 
should be considered invalid by create
+               when(service.getName()).thenReturn("aName");
+               when(service.getType()).thenReturn("aType");
+               RangerServiceDef serviceDef = mock(RangerServiceDef.class);
+               
when(_store.getServiceDefByName("aType")).thenReturn(serviceDef);
+               // test both when service exists and when it doesn't -- the 
result is opposite for the two cases
+               RangerService existingService = mock(RangerService.class);
+               
when(_store.getServiceByName("aName")).thenReturn(existingService);
+
+               _validator = new RangerServiceValidator(_store, Action.CREATE);
+               assertFalse(_validator.isValid(service));
+               
+               // check the error returned: it is a semantic error about 
service's name
+               failures = _validator.getFailures();
+               boolean found = false;
+               for (ValidationFailureDetails f : failures) {
+                       if ("name".equals(f._fieldName) && 
+                                       f._missing == false && 
+                                       f._semanticError == true) {
+                               found = true;
+                       }
+               }
+               assertTrue("Matching failure located", found);
+               
+               // Update: Exact inverse is true, i.e. service must exist!
+               when(_store.getServiceByName("anotherName")).thenReturn(null);
+               when(service.getName()).thenReturn("anotherName");
+               
+               _validator = new RangerServiceValidator(_store, Action.UPDATE);
+               assertFalse(_validator.isValid(service));
+               // check the error returned: it is a semantic error about 
service's name
+               failures = _validator.getFailures();
+               found = false;
+               for (ValidationFailureDetails f : failures) {
+                       if ("name".equals(f._fieldName) && 
+                                       f._missing == false && 
+                                       f._semanticError == true) {
+                               found = true;
+                       }
+               }
+               assertTrue("Matching failure located", found);
+       }
+       
+       @Test
+       public void test_isValid_missingRequiredParameter() throws Exception {
+               // Create/Update: simulate a condition where required 
parameters are missing
+               Object[][] input = new Object[][] {
+                               { "param1", true },
+                               { "param2", true },
+                               { "param3", false },
+                               { "param4", false },
+               };
+               List<RangerServiceConfigDef> configDefs = 
_utils.createServiceConditionDefs(input);
+               RangerServiceDef serviceDef = mock(RangerServiceDef.class);
+               when(serviceDef.getConfigs()).thenReturn(configDefs);
+               // wire this service def into store
+               
when(_store.getServiceDefByName("aType")).thenReturn(serviceDef);
+               // create a service with some require parameters missing
+               RangerService service = mock(RangerService.class);
+               when(service.getType()).thenReturn("aType");
+               when(service.getName()).thenReturn("aName");
+               // required parameters param2 is missing
+               String[] params = new String[] { "param1", "param3", "param4", 
"param5" };
+               Map<String, String> paramMap = _utils.createMap(params);
+               when(service.getConfigs()).thenReturn(paramMap);
+               // service does not exist in the store
+               when(_store.getServiceByName("aService")).thenReturn(null);
+               for (Action action : cu) {
+                       // it should be invalid
+                       _validator = new RangerServiceValidator(_store, action);
+                       assertFalse(_validator.isValid(service));
+                       // check the error message
+                       List<ValidationFailureDetails> failures = 
_validator.getFailures();
+                       boolean found = false;
+                       for (ValidationFailureDetails f : failures) {
+                               if ("configuration".equals(f.getFieldName()) &&
+                                               
"param2".equals(f._subFieldName) &&
+                                               f._missing == true &&
+                                               f._internalError == false && 
+                                               f._semanticError == false) {
+                                       found = true;
+                               }
+                       }
+                       assertTrue(found);
+               }
+       }
+
+       @Test
+       public void test_isValid_happyPath() throws Exception {
+               // create a service def with some required parameters 
+               Object[][] serviceDefInput = new Object[][] {
+                               { "param1", true },
+                               { "param2", true },
+                               { "param3", false },
+                               { "param4", false },
+                               { "param5", true },
+               };
+               List<RangerServiceConfigDef> configDefs = 
_utils.createServiceConditionDefs(serviceDefInput);
+               RangerServiceDef serviceDef = mock(RangerServiceDef.class);
+               when(serviceDef.getConfigs()).thenReturn(configDefs);
+               // create a service with some parameters on it
+               RangerService service = mock(RangerService.class);
+               when(service.getName()).thenReturn("aName");
+               when(service.getType()).thenReturn("aType");
+               // contains an extra parameter (param6) and one optional is 
missing(param4)
+               String[] configs = new String[] { "param1", "param2", "param3", 
"param5", "param6" };
+               Map<String, String> configMap = _utils.createMap(configs);  
+               when(service.getConfigs()).thenReturn(configMap);
+               // wire then into the store
+               try {
+                       // service does not exists
+                       when(_store.getServiceByName("aName")).thenReturn(null);
+                       // service def exists
+                       
when(_store.getServiceDefByName("aType")).thenReturn(serviceDef);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       fail("Unexpected error encountered while mocking!");
+               }
+               _validator = new RangerServiceValidator(_store, Action.CREATE);
+               assertTrue(_validator.isValid(service));
+               // for update to work the only additional requirement is that 
service should exist
+               RangerService existingService = mock(RangerService.class);
+               
when(_store.getServiceByName("aName")).thenReturn(existingService);
+               _validator = new RangerServiceValidator(_store, Action.UPDATE);
+               assertTrue(_validator.isValid(service));
+       }
+
+       ValidationFailureDetails getFailure(List<ValidationFailureDetails> 
failures) {
+               if (failures == null || failures.size() == 0) {
+                       return null;
+               } else {
+                       return failures.iterator().next();
+               }
+       }
+       private ServiceStore _store;
+       private RangerServiceValidator _validator;
+       private Action _action;
+       private ValidationTestUtils _utils = new ValidationTestUtils();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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
new file mode 100644
index 0000000..483e914
--- /dev/null
+++ 
b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceRESTForValidation.java
@@ -0,0 +1,129 @@
+/*
+ * 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.rest;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.apache.ranger.biz.ServiceDBStore;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.rest.RangerValidator.Action;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestServiceRESTForValidation {
+
+       @Before
+       public void setUp() throws Exception {
+               _serviceRest = new ServiceREST();
+               // inject out store in it
+               _store = mock(ServiceDBStore.class);
+               _serviceRest.svcStore = _store;
+               // and our validator factory
+               _action = Action.CREATE;
+               _factory = mock(RangerValidatorFactory.class);
+               _validator = mock(RangerServiceValidator.class);
+               when(_factory.getServiceValidator(_store, 
_action)).thenReturn(_validator);
+               _serviceRest.validatorFactory = _factory;
+               // and other things that are needed for service rest to work 
correctly
+               _restErrorUtil = mock(RESTErrorUtil.class);
+               WebApplicationException webApplicationException = new 
WebApplicationException();
+               when(_restErrorUtil.createRESTException(anyInt(), anyString(), 
anyBoolean())).thenReturn(webApplicationException);
+               _serviceRest.restErrorUtil = _restErrorUtil;
+               // other object of use in multiple tests
+               _service = mock(RangerService.class);
+               _exception = new Exception();
+       }
+
+       @Test
+       public final void testCreateService_happyPath() throws Exception {
+               // creation should succeed if neither validator nor dbstore 
throw exception
+               when(_store.createService(_service)).thenReturn(null); // 
return value isn't important
+               // by default validator mock would not throw exception!
+               try {
+                       _serviceRest.createService(_service);
+                       // validator must be excercised
+                       verify(_validator).validate(_service);
+                       // db store would also have been excercised but that is 
not the focus of this test!!
+               } catch (Throwable t) {
+                       t.printStackTrace();
+                       fail("Unexpected exception thrown!");
+               }
+       }
+
+       @Test
+       public final void testCreateService_failureStore() throws Exception {
+               // creation should fail if either validator or dbstore throw 
exception
+               // first have only the dbstore throw and exception
+               when(_store.createService(_service)).thenThrow(_exception);
+               // by default validator mock would not throw exception!
+               try {
+                       _serviceRest.createService(_service);
+                       fail("Should have thrown an exception!");
+               } catch (WebApplicationException t) {
+                       // expected exception - confirm that validator was 
excercised
+                       verify(_validator).validate(_service);
+               } catch (Throwable t) {
+                       fail("Unexpected exception thrown!");
+               }
+       }
+
+       @Test
+       public final void testCreateService_failureValidator() throws Exception 
{
+               // creation should fail if either validator or dbstore throw 
exception
+               // Now we only have the 
+               doThrow(_exception).when(_validator).validate(_service);
+               // by default validator mock would not throw exception!
+               try {
+                       _serviceRest.createService(_service);
+                       fail("Should have thrown an exception!");
+               } catch (WebApplicationException t) {
+                       /*
+                        * Expected exception - but we still need to validate 
two things:
+                        * - That validator was exercised; accidentally call to 
validator should not get bypassed.
+                        * - That dbstore was NOT exercised; we expect 
validator failure to short circuit that
+                        */
+                       verify(_validator).validate(_service);
+                       // And that db store was never called!  We don't expect 
call to go to it if validator throws exception.
+                       verify(_store, never()).createService(_service);
+               } catch (Throwable t) {
+                       fail("Unexpected exception thrown!");
+               }
+       }
+
+       RangerValidatorFactory _factory;
+       RangerServiceValidator _validator;
+       ServiceDBStore _store;
+       Action _action;
+       ServiceREST _serviceRest;
+       RangerService _service;
+       Exception _exception;
+       RESTErrorUtil _restErrorUtil;
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/security-admin/src/test/java/org/apache/ranger/rest/TestServiceValidator.java
----------------------------------------------------------------------
diff --git 
a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceValidator.java 
b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceValidator.java
new file mode 100644
index 0000000..a1879c4
--- /dev/null
+++ 
b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceValidator.java
@@ -0,0 +1,202 @@
+/*
+ * 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.rest;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
+import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.rest.RangerValidator.Action;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestServiceValidator {
+
+       static class TestRangerValidator extends RangerValidator {
+
+               public TestRangerValidator(ServiceStore store, Action action) {
+                       super(store, action);
+               }
+               
+               boolean isValid(String behavior) {
+                       if (behavior.equals("valid")) {
+                               _valid = true;
+                       } else {
+                               _valid = false;
+                               if (behavior.equals("reason")) {
+                                       _failures = new 
ArrayList<ValidationFailureDetails>();
+                                       _failures.add(new 
ValidationFailureDetails("", "", false, false, false, ""));
+                               }
+                       }
+                       return _valid;
+               }
+       }
+       
+       @Before
+       public void before() {
+               _store = mock(ServiceStore.class);
+               _validator = new TestRangerValidator(_store, Action.CREATE);
+       }
+
+       @Test
+       public void test_ctor_firewalling() {
+               try {
+                       // service store can't be null during construction  
+                       new TestRangerValidator(null, Action.CREATE);
+                       fail("Should have thrown exception!");
+               } catch (IllegalArgumentException e) {
+                       // expected exception
+               }
+               try {
+                       // action can't be null
+                       new TestRangerValidator(_store, null);
+                       fail("Should have thrown exception!");
+               } catch (IllegalArgumentException e) {
+                       // expected exception
+               }
+       }
+
+       public void test_getFailures_firewalling() {
+               // it is illegal to query validator for reason without first 
having it check something!
+               try {
+                       _validator.getFailures();
+                       fail("Should have thrown exception!");
+               } catch (IllegalStateException e) {
+                       // expected exception.
+               }
+               
+               try {
+                       // we know this call will fail
+                       _validator.isValid("invalid");
+                       _validator.getFailures();
+               } catch (Throwable t) {
+                       t.printStackTrace();
+                       fail("Unexpected exception!");
+               }
+       }
+       
+       @Test
+       public void test_getServiceConfigParameters() {
+               // reasonable protection against null values
+               Set<String> parameters = 
_validator.getServiceConfigParameters(null);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+               
+               RangerService service = mock(RangerService.class);
+               when(service.getConfigs()).thenReturn(null);
+               parameters = _validator.getServiceConfigParameters(service);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+               
+               when(service.getConfigs()).thenReturn(new HashMap<String, 
String>());
+               parameters = _validator.getServiceConfigParameters(service);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+
+               String[] keys = new String[] { "a", "b", "c" };
+               Map<String, String> map = _utils.createMap(keys);
+               when(service.getConfigs()).thenReturn(map);
+               parameters = _validator.getServiceConfigParameters(service);
+               for (String key: keys) {
+                       assertTrue("key", parameters.contains(key));
+               }
+       }
+       
+       @Test
+       public void test_getRequiredParameters() {
+               // reasonable protection against null things
+               Set<String> parameters = _validator.getRequiredParameters(null);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+
+               RangerServiceDef serviceDef = mock(RangerServiceDef.class);
+               when(serviceDef.getConfigs()).thenReturn(null);
+               parameters = _validator.getRequiredParameters(null);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+
+               List<RangerServiceConfigDef> configs = new 
ArrayList<RangerServiceDef.RangerServiceConfigDef>();
+               when(serviceDef.getConfigs()).thenReturn(configs);
+               parameters = _validator.getRequiredParameters(null);
+               assertNotNull(parameters);
+               assertTrue(parameters.isEmpty());
+               
+               Object[][] input = new Object[][] {
+                               { "param1", false },
+                               { "param2", true },
+                               { "param3", true },
+                               { "param4", false },
+               };
+               configs = _utils.createServiceConditionDefs(input);
+               when(serviceDef.getConfigs()).thenReturn(configs);
+               parameters = _validator.getRequiredParameters(serviceDef);
+               assertTrue("result does not contain: param2", 
parameters.contains("param2"));
+               assertTrue("result does not contain: param3", 
parameters.contains("param3"));
+       }
+       
+       @Test
+       public void test_getServiceDef() {
+               try {
+                       // if service store returns null or throws an exception 
then service is deemed invalid
+                       when(_store.getServiceDefByName("return 
null")).thenReturn(null);
+                       when(_store.getServiceDefByName("throw")).thenThrow(new 
Exception());
+                       RangerServiceDef serviceDef = 
mock(RangerServiceDef.class);
+                       
when(_store.getServiceDefByName("good-service")).thenReturn(serviceDef);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       fail("Unexpected exception during mocking!");
+               }
+               
+               assertNull(_validator.getServiceDef("return null"));
+               assertNull(_validator.getServiceDef("throw"));
+               assertFalse(_validator.getServiceDef("good-service") == null);
+       }
+
+       @Test
+       public void test_getService() {
+               try {
+                       // if service store returns null or throws an exception 
then service is deemed invalid
+                       when(_store.getServiceByName("return 
null")).thenReturn(null);
+                       when(_store.getServiceByName("throw")).thenThrow(new 
Exception());
+                       RangerService service = mock(RangerService.class);
+                       
when(_store.getServiceByName("good-service")).thenReturn(service);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       fail("Unexpected exception during mocking!");
+               }
+               
+               assertNull(_validator.getService("return null"));
+               assertNull(_validator.getService("throw"));
+               assertFalse(_validator.getService("good-service") == null);
+       }
+
+       private TestRangerValidator _validator;
+       private ServiceStore _store;
+       private ValidationTestUtils _utils = new ValidationTestUtils();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/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
new file mode 100644
index 0000000..0925aa1
--- /dev/null
+++ 
b/security-admin/src/test/java/org/apache/ranger/rest/ValidationTestUtils.java
@@ -0,0 +1,57 @@
+/*
+ * 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.rest;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerServiceConfigDef;
+
+public class ValidationTestUtils {
+       
+       Map<String, String> createMap(String[] keys) {
+               Map<String, String> result = new HashMap<String, String>();
+               for (String key : keys) {
+                       result.put(key, "valueof-" + key);
+               }
+               return result;
+       }
+
+       // helper methods for tests
+       List<RangerServiceConfigDef> createServiceConditionDefs(Object[][] 
input) {
+               List<RangerServiceConfigDef> result = new 
ArrayList<RangerServiceDef.RangerServiceConfigDef>();
+               
+               for (Object data[] : input) {
+                       RangerServiceConfigDef aConfigDef = 
mock(RangerServiceConfigDef.class);
+                       when(aConfigDef.getName()).thenReturn((String)data[0]);
+                       
when(aConfigDef.getMandatory()).thenReturn((boolean)data[1]);
+                       result.add(aConfigDef);
+               }
+               
+               return result;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/d69fc28d/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
----------------------------------------------------------------------
diff --git 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
index f2fbf02..b6bb811 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
@@ -39,7 +39,6 @@ import javax.naming.ldap.LdapContext;
 import javax.naming.ldap.PagedResultsControl;
 import javax.naming.ldap.PagedResultsResponseControl;
 
-import com.sun.jndi.toolkit.dir.SearchFilter;
 import org.apache.log4j.Logger;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
 import org.apache.ranger.usergroupsync.UserGroupSink;

Reply via email to