ranger-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ab...@apache.org
Subject [4/4] ranger git commit: RANGER-2000: Policy effective dates to support time-bound and temporary authorization
Date Mon, 05 Mar 2018 06:27:13 GMT
RANGER-2000: Policy effective dates to support time-bound and temporary authorization


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

Branch: refs/heads/master
Commit: 844315cdbc5e4589f5a4f873c33533d8f7bb014e
Parents: 7037920
Author: Abhay Kulkarni <akulkarni@hortonworks.com>
Authored: Sun Mar 4 22:08:21 2018 -0800
Committer: Abhay Kulkarni <akulkarni@hortonworks.com>
Committed: Sun Mar 4 22:08:21 2018 -0800

----------------------------------------------------------------------
 .../ranger/authorization/utils/JsonUtils.java   | 121 ++++
 .../contextenricher/RangerTagEnricher.java      |   8 +-
 .../contextenricher/RangerTagForEval.java       | 129 +++-
 .../plugin/errors/ValidationErrorCode.java      |   2 +
 .../ranger/plugin/model/RangerPolicy.java       | 105 +++-
 .../model/RangerPolicyResourceSignature.java    |  10 +-
 .../apache/ranger/plugin/model/RangerTag.java   |  77 ++-
 .../plugin/model/RangerValidityRecurrence.java  | 231 +++++++
 .../plugin/model/RangerValiditySchedule.java    |  93 +++
 .../model/validation/RangerPolicyValidator.java |  51 +-
 .../model/validation/RangerValidator.java       |   2 +-
 .../RangerValidityScheduleValidator.java        | 480 +++++++++++++++
 .../policyengine/PolicyEvaluatorForTag.java     |  61 +-
 .../plugin/policyengine/RangerAccessResult.java |   6 +
 .../policyengine/RangerPolicyEngineImpl.java    |  67 ++-
 .../policyengine/RangerPolicyRepository.java    |  35 +-
 .../RangerAbstractPolicyEvaluator.java          |   5 +
 ...angerDefaultDataMaskPolicyItemEvaluator.java |   5 +-
 .../RangerDefaultPolicyEvaluator.java           |  49 +-
 .../RangerDefaultPolicyItemEvaluator.java       |   4 +-
 ...ngerDefaultRowFilterPolicyItemEvaluator.java |   4 +-
 .../policyevaluator/RangerPolicyEvaluator.java  |  35 ++
 .../RangerPolicyItemEvaluator.java              |   3 +-
 .../RangerValidityScheduleEvaluator.java        | 588 ++++++++++++++++++
 .../ScheduledTimeAlwaysMatcher.java             |  27 +
 .../ScheduledTimeExactMatcher.java              |  32 +
 .../resourcematcher/ScheduledTimeMatcher.java   |  24 +
 .../ScheduledTimeRangeMatcher.java              |  34 ++
 .../plugin/store/AbstractPredicateUtil.java     | 116 ++--
 .../apache/ranger/plugin/util/SearchFilter.java |   1 +
 .../plugin/policyengine/TestPolicyEngine.java   |  99 ++-
 agents-common/src/test/resources/log4j.xml      |   4 +-
 .../test_policyengine_temporary.json            | 347 +++++++++++
 .../test-validity-schedules-invalid.json        | 146 +++++
 ...validity-schedules-valid-and-applicable.json | 507 ++++++++++++++++
 .../test-validity-schedules-valid.json          | 152 +++++
 .../optimized/current/ranger_core_db_mysql.sql  |   3 +
 ...policy-and-tag-for-time-based-processing.sql |  44 ++
 .../optimized/current/ranger_core_db_oracle.sql |   3 +
 ...policy-and-tag-for-time-based-processing.sql |  34 ++
 .../current/ranger_core_db_postgres.sql         |   3 +
 ...policy-and-tag-for-time-based-processing.sql |  53 ++
 .../current/ranger_core_db_sqlanywhere.sql      |   3 +
 ...policy-and-tag-for-time-based-processing.sql |  29 +
 .../current/ranger_core_db_sqlserver.sql        |   3 +
 ...policy-and-tag-for-time-based-processing.sql |  35 ++
 .../ranger/biz/RangerPolicyRetriever.java       |  96 +--
 .../apache/ranger/biz/RangerTagDBRetriever.java |  17 +-
 .../java/org/apache/ranger/biz/TagDBStore.java  |  41 +-
 .../apache/ranger/common/RangerSearchUtil.java  |   4 +-
 .../org/apache/ranger/entity/XXPolicyBase.java  |  67 ++-
 .../java/org/apache/ranger/entity/XXTag.java    |  20 +-
 .../ranger/service/RangerPolicyServiceBase.java |  47 +-
 .../ranger/service/RangerTagServiceBase.java    |  32 +
 src/main/assembly/tagsync.xml                   |   1 +
 .../source/atlas/AtlasNotificationMapper.java   | 603 ++++++++++---------
 .../tagsync/source/atlas/AtlasTagSource.java    |   2 +-
 .../source/atlas/EntityNotificationWrapper.java | 395 ++++++------
 .../source/atlasrest/AtlasRESTTagSource.java    | 287 +++++----
 .../atlasrest/RangerAtlasEntityWithTags.java    |  81 +--
 60 files changed, 4738 insertions(+), 825 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java b/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
new file mode 100644
index 0000000..bc4a8b5
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/authorization/utils/JsonUtils.java
@@ -0,0 +1,121 @@
+/*
+ * 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.authorization.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.model.RangerValidityRecurrence;
+import org.apache.ranger.plugin.model.RangerValiditySchedule;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JsonUtils {
+    private static final Log LOG = LogFactory.getLog(JsonUtils.class);
+
+    private static final HashMap<String, String> MAP_STRING_STRING = new HashMap<>();
+
+    private static final Gson gson;
+
+    static {
+        gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z")
+                .setPrettyPrinting()
+                .create();
+    }
+
+    public static String mapToJson(Map<?, ?> map) {
+        String ret = null;
+        if (MapUtils.isNotEmpty(map)) {
+            try {
+                ret = gson.toJson(map);
+            } catch (Exception e) {
+                LOG.error("Invalid input data: ", e);
+            }
+        }
+        return ret;
+    }
+
+    public static String listToJson(List<?> list) {
+        String ret = null;
+        if (CollectionUtils.isNotEmpty(list)) {
+            try {
+                ret = gson.toJson(list);
+            } catch (Exception e) {
+                LOG.error("Invalid input data: ", e);
+            }
+        }
+        return ret;
+    }
+
+    public static <T> T jsonToObject(String jsonStr, Class<T> clz) {
+        T ret = null;
+
+        if(StringUtils.isNotEmpty(jsonStr)) {
+            try {
+                ret = gson.fromJson(jsonStr, clz);
+            } catch(Exception excp) {
+                LOG.warn("jsonToObject() failed to convert json to object: " + jsonStr, excp);
+            }
+        }
+
+        return ret;
+    }
+
+    public static Map<String, String> jsonToMapStringString(String jsonStr) {
+        Map<String, String> ret = null;
+
+        if(StringUtils.isNotEmpty(jsonStr)) {
+            try {
+                ret = gson.fromJson(jsonStr, MAP_STRING_STRING.getClass());
+            } catch(Exception excp) {
+                LOG.warn("jsonToObject() failed to convert json to object: " + jsonStr, excp);
+            }
+        }
+
+        return ret;
+    }
+
+    public static List<RangerValiditySchedule> jsonToRangerValiditySchedule(String jsonStr) {
+        try {
+            Type listType = new TypeToken<List<RangerValiditySchedule>>() {
+            }.getType();
+            return gson.fromJson(jsonStr, listType);
+        } catch (Exception e) {
+            LOG.error("Cannot get List<RangerValiditySchedule> from " + jsonStr, e);
+            return null;
+        }
+    }
+    public static List<RangerValidityRecurrence> jsonToRangerValidityRecurringSchedule(String jsonStr) {
+        try {
+            Type listType = new TypeToken<List<RangerValidityRecurrence>>() {
+            }.getType();
+            return gson.fromJson(jsonStr, listType);
+        } catch (Exception e) {
+            LOG.error("Cannot get List<RangerValidityRecurrence> from " + jsonStr, e);
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
index 415d4a4..d5d14a2 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
@@ -335,10 +335,12 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			}
 		}
 
-		if (LOG.isDebugEnabled()) {
-			if (CollectionUtils.isEmpty(ret)) {
+		if (CollectionUtils.isEmpty(ret)) {
+			if (LOG.isDebugEnabled()) {
 				LOG.debug("RangerTagEnricher.findMatchingTags(" + resource + ") - No tags Found ");
-			} else {
+			}
+		} else {
+			if (LOG.isDebugEnabled()) {
 				LOG.debug("RangerTagEnricher.findMatchingTags(" + resource + ") - " + ret.size() + " tags Found ");
 			}
 		}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagForEval.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagForEval.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagForEval.java
index e31efa3..524605d 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagForEval.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagForEval.java
@@ -19,9 +19,17 @@
 
 package org.apache.ranger.plugin.contextenricher;
 
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.authorization.utils.JsonUtils;
 import org.apache.ranger.plugin.model.RangerTag;
+import org.apache.ranger.plugin.model.RangerValiditySchedule;
+import org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
 import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonIgnoreProperties;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
@@ -29,6 +37,10 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
 @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
@@ -41,26 +53,80 @@ import java.util.Map;
 // from JSON specification
 
 public class RangerTagForEval implements Serializable {
-    private String type;
-    private Map<String, String> attributes;
+    private static final Log LOG = LogFactory.getLog(RangerTagForEval.class);
+
+    private String                                type;
+    private Map<String, String>                   attributes;
+    private Map<String, Object>                   options;
     private RangerPolicyResourceMatcher.MatchType matchType = RangerPolicyResourceMatcher.MatchType.SELF;
+    @JsonIgnore
+    private List<RangerValiditySchedule>          validityPeriods;
+    @JsonIgnore
+    private List<RangerValidityScheduleEvaluator> validityPeriodEvaluators;
+
 
     private RangerTagForEval() {}
 
     public RangerTagForEval(RangerTag tag, RangerPolicyResourceMatcher.MatchType matchType) {
-        this.type = tag.getType();
-        this.attributes = tag.getAttributes();
-        this.matchType = matchType;
-    }
+        this.type            = tag.getType();
+        this.attributes      = tag.getAttributes();
+        this.options         = tag.getOptions();
+        this.matchType       = matchType;
+        this.validityPeriods = tag.getValidityPeriods();
 
-    public RangerPolicyResourceMatcher.MatchType getMatchType() {
-        return matchType;
+        this.validityPeriodEvaluators = createValidityPeriodEvaluators();
     }
 
     public String getType() { return type;}
 
-    public Map<String, String> getAttributes() {
-        return attributes;
+    public Map<String, String> getAttributes() { return attributes; }
+
+    public Map<String, Object> getOptions() { return options; }
+
+    public RangerPolicyResourceMatcher.MatchType getMatchType() { return matchType; }
+
+    public List<RangerValiditySchedule> getValidityPeriods() { return validityPeriods; }
+
+    public boolean isApplicable(Date accessTime) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerTagForEval.isApplicable(type=" + type + ", " + accessTime + ")");
+        }
+
+        boolean ret = false;
+
+        List<RangerValidityScheduleEvaluator> validityPeriodEvaluators = this.validityPeriodEvaluators;
+
+        // Specifically for unit-testing using TestPolicyEngine
+        if (MapUtils.isNotEmpty(options) && CollectionUtils.isEmpty(validityPeriodEvaluators)) {
+            Object value = getOption(RangerTag.OPTION_TAG_VALIDITY_PERIODS);
+
+            if (value != null && value instanceof String) {
+                this.validityPeriods = JsonUtils.jsonToRangerValiditySchedule((String) value);
+
+                validityPeriodEvaluators = createValidityPeriodEvaluators();
+            } else {
+                validityPeriodEvaluators = Collections.emptyList();
+            }
+
+            this.validityPeriodEvaluators = validityPeriodEvaluators;
+        }
+
+        if (accessTime != null && CollectionUtils.isNotEmpty(validityPeriodEvaluators)) {
+            for (RangerValidityScheduleEvaluator evaluator : validityPeriodEvaluators) {
+                if (evaluator.isApplicable(accessTime.getTime())) {
+                    ret = true;
+                    break;
+                }
+            }
+        } else {
+            ret = true;
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RangerTagForEval.isApplicable(type=" + type + ", " + accessTime + ") : " + ret);
+        }
+
+        return ret;
     }
 
     @Override
@@ -83,6 +149,14 @@ public class RangerTagForEval implements Serializable {
         }
         sb.append(" }");
         sb.append(", matchType=").append(matchType);
+
+        if (options != null) {
+            sb.append(", options={").append(options).append("}");
+        }
+
+        if (validityPeriods != null) {
+            sb.append(", validityPeriods=").append(validityPeriods);
+        }
         sb.append(" }");
         return sb;
     }
@@ -97,6 +171,11 @@ public class RangerTagForEval implements Serializable {
                 + ((attributes == null) ? 0 : attributes.hashCode());
         result = prime * result
                 + ((matchType == null) ? 0 : matchType.hashCode());
+        result = prime * result
+                + ((validityPeriods == null) ? 0 : validityPeriods.hashCode());
+        result = prime * result
+                + ((options == null) ? 0 : options.hashCode());
+
         return result;
     }
 
@@ -124,7 +203,37 @@ public class RangerTagForEval implements Serializable {
                 return false;
         } else if (!matchType.equals(other.matchType))
             return false;
+        if (options == null) {
+            if (other.options != null)
+                return false;
+        } else if (!options.equals(other.options))
+            return false;
+        if (validityPeriods == null) {
+            if (other.validityPeriods != null)
+                return false;
+        } else if (!validityPeriods.equals(other.validityPeriods))
+            return false;
 
         return true;
     }
+
+    private Object getOption(String name) {
+        return options != null ? options.get(name) : null;
+    }
+
+    private List<RangerValidityScheduleEvaluator> createValidityPeriodEvaluators() {
+        final List<RangerValidityScheduleEvaluator> ret;
+
+        if (CollectionUtils.isNotEmpty(validityPeriods)) {
+            ret = new ArrayList<>();
+
+            for (RangerValiditySchedule schedule : validityPeriods) {
+                ret.add(new RangerValidityScheduleEvaluator(schedule));
+            }
+        } else {
+            ret = Collections.emptyList();
+        }
+
+        return ret;
+    }
 }

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
index a7f7c39..ab120b7 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
@@ -91,6 +91,8 @@ public enum ValidationErrorCode {
     POLICY_VALIDATION_ERR_MISSING_RESOURCE_LIST(3026, "Resource list was empty or contains null. At least one resource must be specified"),
     POLICY_VALIDATION_ERR_POLICY_UPDATE_MOVE_SERVICE_NOT_ALLOWED(3027, "attempt to move policy id={0} from service={1} to service={2} is not allowed"),
     POLICY_VALIDATION_ERR_POLICY_TYPE_CHANGE_NOT_ALLOWED(3028, "attempt to change type of policy id={0} from type={1} to type={2} is not allowed"),
+    POLICY_VALIDATION_ERR_POLICY_INVALID_VALIDITY_SCHEDULE(3029, "Invalid validity schedule specification"),
+    POLICY_VALIDATION_ERR_POLICY_INVALID_PRIORITY(3030, "Invalid priority value"),
    ;
 
 

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
index 534fe49..c2185a7 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
@@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.commons.collections.CollectionUtils;
 import org.codehaus.jackson.annotate.JsonAutoDetect;
 import org.codehaus.jackson.annotate.JsonIgnoreProperties;
 import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
@@ -54,12 +55,19 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 	public static final String MASK_TYPE_NONE   = "MASK_NONE";
 	public static final String MASK_TYPE_CUSTOM = "CUSTOM";
 
+	public static final int POLICY_PRIORITY_NORMAL   = 0;
+	public static final int POLICY_PRIORITY_OVERRIDE = 1;
+
+	public static final String POLICY_PRIORITY_NAME_NORMAL   = "NORMAL";
+	public static final String POLICY_PRIORITY_NAME_OVERRIDE = "OVERRIDE";
+
 	// For future use
 	private static final long serialVersionUID = 1L;
 
 	private String                            service;
 	private String                            name;
 	private Integer                           policyType;
+	private Integer                           policyPriority;
 	private String                            description;
 	private String							  resourceSignature;
 	private Boolean                           isAuditEnabled;
@@ -70,15 +78,13 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 	private List<RangerPolicyItem>            denyExceptions;
 	private List<RangerDataMaskPolicyItem>    dataMaskPolicyItems;
 	private List<RangerRowFilterPolicyItem>   rowFilterPolicyItems;
-  private String                            serviceType;
-  private List<String> policyLabels;
+	private String                            serviceType;
+	private Map<String, Object>               options;
+	private List<RangerValiditySchedule>      validitySchedules;
+	private List<String>                      policyLabels;
 
-
-	/**
-	 * @param
-	 */
 	public RangerPolicy() {
-                this(null, null, null, null, null, null, null, null);
+		this(null, null, null, null, null, null, null, null, null, null, null);
 	}
 
 	/**
@@ -90,12 +96,13 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 	 * @param policyItems
 	 * @param resourceSignature TODO
 	 */
-        public RangerPolicy(String service, String name, Integer policyType, String description, Map<String, RangerPolicyResource> resources, List<RangerPolicyItem> policyItems, String resourceSignature, List<String> policyLables) {
+	public RangerPolicy(String service, String name, Integer policyType, Integer policyPriority, String description, Map<String, RangerPolicyResource> resources, List<RangerPolicyItem> policyItems, String resourceSignature, Map<String, Object> options, List<RangerValiditySchedule> validitySchedules, List<String> policyLables) {
 		super();
 
 		setService(service);
 		setName(name);
 		setPolicyType(policyType);
+		setPolicyPriority(policyPriority);
 		setDescription(description);
 		setResourceSignature(resourceSignature);
 		setIsAuditEnabled(null);
@@ -106,7 +113,10 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		setDenyExceptions(null);
 		setDataMaskPolicyItems(null);
 		setRowFilterPolicyItems(null);
-                setPolicyLabels(policyLables);
+		setOptions(options);
+		setValiditySchedules(validitySchedules);
+		setPolicyLabels(policyLables);
+
 	}
 
 	/**
@@ -118,6 +128,7 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		setService(other.getService());
 		setName(other.getName());
 		setPolicyType(other.getPolicyType());
+		setPolicyPriority(other.getPolicyPriority());
 		setDescription(other.getDescription());
 		setResourceSignature(other.getResourceSignature());
 		setIsAuditEnabled(other.getIsAuditEnabled());
@@ -128,7 +139,9 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		setDenyExceptions(other.getDenyExceptions());
 		setDataMaskPolicyItems(other.getDataMaskPolicyItems());
 		setRowFilterPolicyItems(other.getRowFilterPolicyItems());
-                setPolicyLabels(other.getPolicyLabels());
+		setOptions(other.getOptions());
+		setValiditySchedules(other.getValiditySchedules());
+		setPolicyLabels(other.getPolicyLabels());
 	}
 
 	/**
@@ -174,6 +187,20 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 	}
 
 	/**
+	 * @return the policyPriority
+	 */
+	public Integer getPolicyPriority() {
+		return policyPriority;
+	}
+
+	/**
+	 * @param policyPriority the policyPriority to set
+	 */
+	public void setPolicyPriority(Integer policyPriority) {
+		this.policyPriority = policyPriority == null ? RangerPolicy.POLICY_PRIORITY_NORMAL : policyPriority;
+	}
+
+	/**
 	 * @return the description
 	 */
 	public String getDescription() {
@@ -415,6 +442,40 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		}
 	}
 
+    public Map<String, Object> getOptions() { return options; }
+
+    public void setOptions(Map<String, Object> options) {
+	    if (this.options == null) {
+	        this.options = new HashMap<>();
+        }
+        if (this.options == options) {
+	        return;
+        }
+        this.options.clear();
+
+        if(options != null) {
+            for(Map.Entry<String, Object> e : options.entrySet()) {
+                this.options.put(e.getKey(), e.getValue());
+            }
+        }
+    }
+
+    public List<RangerValiditySchedule> getValiditySchedules() { return validitySchedules; }
+
+    public void setValiditySchedules(List<RangerValiditySchedule> validitySchedules) {
+        if (this.validitySchedules == null) {
+            this.validitySchedules = new ArrayList<>();
+        }
+        if (this.validitySchedules == validitySchedules) {
+            return;
+        }
+        this.validitySchedules.clear();
+
+        if(validitySchedules != null) {
+            this.validitySchedules.addAll(validitySchedules);
+        }
+    }
+
 	@Override
 	public String toString( ) {
 		StringBuilder sb = new StringBuilder();
@@ -432,10 +493,11 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		sb.append("service={").append(service).append("} ");
 		sb.append("name={").append(name).append("} ");
 		sb.append("policyType={").append(policyType).append("} ");
+		sb.append("policyPriority={").append(policyPriority).append("} ");
 		sb.append("description={").append(description).append("} ");
 		sb.append("resourceSignature={").append(resourceSignature).append("} ");
 		sb.append("isAuditEnabled={").append(isAuditEnabled).append("} ");
-                sb.append("serviceType={").append(serviceType).append("} ");
+		sb.append("serviceType={").append(serviceType).append("} ");
 
 		sb.append("resources={");
 		if(resources != null) {
@@ -515,6 +577,27 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		}
 		sb.append("} ");
 
+        sb.append("options={");
+        if(options != null) {
+            for(Map.Entry<String, Object> e : options.entrySet()) {
+                sb.append(e.getKey()).append("={");
+                sb.append(e.getValue().toString());
+                sb.append("} ");
+            }
+        }
+        sb.append("} ");
+
+        //sb.append("validitySchedules={").append(validitySchedules).append("} ");
+        sb.append("validitySchedules={");
+        if (CollectionUtils.isNotEmpty(validitySchedules)) {
+            for (RangerValiditySchedule schedule : validitySchedules) {
+                if (schedule != null) {
+                    sb.append("schedule={").append(schedule).append("}");
+                }
+            }
+        }
+        sb.append("}");
+
 		sb.append("}");
 
 		return sb;

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
index 00e60e2..b56b8dd 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyResourceSignature.java
@@ -27,6 +27,7 @@ import java.util.Objects;
 import java.util.TreeMap;
 
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
@@ -45,7 +46,7 @@ public class RangerPolicyResourceSignature {
 		_policy = policy;
 		PolicySerializer serializer = new PolicySerializer(_policy);
 		_string = serializer.toString();
-                _hash = DigestUtils.sha256Hex(_string);
+		_hash = DigestUtils.sha256Hex(_string);
 	}
 
 	/**
@@ -136,6 +137,13 @@ public class RangerPolicyResourceSignature {
 				resources.put(resourceName, resourceView);
 			}
 			String resource = resources.toString();
+			if (CollectionUtils.isNotEmpty(_policy.getValiditySchedules())) {
+				resource += _policy.getValiditySchedules().toString();
+			}
+			if (_policy.getPolicyPriority() != null && _policy.getPolicyPriority() != RangerPolicy.POLICY_PRIORITY_NORMAL) {
+				resource += _policy.getPolicyPriority();
+			}
+
 			String result = String.format("{version=%d,type=%d,resource=%s}", _SignatureVersion, type, resource);
 			return result;
 		}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerTag.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerTag.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerTag.java
index 743b028..9e620c3 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerTag.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerTag.java
@@ -26,7 +26,9 @@ import org.codehaus.jackson.map.annotate.JsonSerialize;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
@@ -40,12 +42,15 @@ public class RangerTag extends RangerBaseModelObject {
 	public static final short OWNER_SERVICERESOURCE = 0;
 	public static final short OWNER_GLOBAL          = 1;
 
-	private String              type;
-    private Short               owner = OWNER_SERVICERESOURCE;
+	public static final String OPTION_TAG_VALIDITY_PERIODS = "TAG_VALIDITY_PERIODS";
 
-	private Map<String, String> attributes;
+	private String                       type;
+	private Short                        owner = OWNER_SERVICERESOURCE;
+	private Map<String, String>          attributes;
+	private Map<String, Object>          options;
+	private List<RangerValiditySchedule> validityPeriods;
 
-	public RangerTag(String guid, String type, Map<String, String> attributes, Short owner) {
+	public RangerTag(String guid, String type, Map<String, String> attributes, Short owner, Map<String, Object> options, List<RangerValiditySchedule> validityPeriods) {
 		super();
 
 		setGuid(guid);
@@ -53,14 +58,20 @@ public class RangerTag extends RangerBaseModelObject {
 		setOwner(owner);
 		setAttributes(attributes);
 		setOwner(owner);
+		setOptions(options);
+		setValidityPeriods(validityPeriods);
+	}
+
+	public RangerTag(String guid, String type, Map<String, String> attributes, Short owner) {
+		this(guid, type, attributes, owner, null, null);
 	}
 
 	public RangerTag(String type, Map<String, String> attributes) {
-		this(null, type, attributes, OWNER_SERVICERESOURCE);
+		this(null, type, attributes, OWNER_SERVICERESOURCE, null, null);
 	}
 
 	public RangerTag() {
-		this(null, null, null, OWNER_SERVICERESOURCE);
+		this(null, null, null, OWNER_SERVICERESOURCE, null, null);
 	}
 
 	public String getType() {
@@ -87,6 +98,39 @@ public class RangerTag extends RangerBaseModelObject {
 		this.owner = owner;
 	}
 
+	public Map<String, Object> getOptions() { return options; }
+
+	public void setOptions(Map<String, Object> options) {
+		if (this.options == null) {
+			this.options = new HashMap<>();
+		}
+		if (this.options == options) {
+			return;
+		}
+		this.options.clear();
+
+		if(options != null) {
+			for(Map.Entry<String, Object> e : options.entrySet()) {
+				this.options.put(e.getKey(), e.getValue());
+			}
+		}
+	}
+
+	public List<RangerValiditySchedule> getValidityPeriods() { return validityPeriods; }
+
+	public void setValidityPeriods(List<RangerValiditySchedule> validityPeriods) {
+		if (this.validityPeriods == null) {
+			this.validityPeriods = new ArrayList<>();
+		}
+		if (this.validityPeriods == validityPeriods) {
+			return;
+		}
+		this.validityPeriods.clear();
+
+		if(validityPeriods != null) {
+			this.validityPeriods.addAll(validityPeriods);
+		}
+	}
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
@@ -114,7 +158,12 @@ public class RangerTag extends RangerBaseModelObject {
 		}
 		sb.append("} ");
 
-		sb.append(" }");
+		if (validityPeriods != null) {
+            sb.append("validityPeriods={").append(validityPeriods).append("} ");
+        }
+		sb.append("options={").append(options).append("} ");
+
+        sb.append(" }");
 
 		return sb;
 	}
@@ -129,6 +178,10 @@ public class RangerTag extends RangerBaseModelObject {
 				+ ((owner == null) ? 0 : owner.hashCode());
 		result = prime * result
 				+ ((attributes == null) ? 0 : attributes.hashCode());
+		result = prime * result
+				+ ((options == null) ? 0 : options.hashCode());
+		result = prime * result
+				+ ((validityPeriods == null) ? 0 : validityPeriods.hashCode());
 		return result;
 	}
 
@@ -156,6 +209,16 @@ public class RangerTag extends RangerBaseModelObject {
 				return false;
 		} else if (!attributes.equals(other.attributes))
 			return false;
+		if (options == null) {
+			if (other.options != null)
+				return false;
+		} else if (!options.equals(other.options))
+			return false;
+		if (validityPeriods == null) {
+			if (other.validityPeriods != null)
+				return false;
+		} else if (!validityPeriods.equals(other.validityPeriods))
+			return false;
 		return true;
 	}
 }

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValidityRecurrence.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValidityRecurrence.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValidityRecurrence.java
new file mode 100644
index 0000000..4bff3ea
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValidityRecurrence.java
@@ -0,0 +1,231 @@
+/*
+ * 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.plugin.model;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@JsonAutoDetect(fieldVisibility= JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+
+public class RangerValidityRecurrence {
+
+    @JsonAutoDetect(fieldVisibility= JsonAutoDetect.Visibility.ANY)
+    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+    @JsonIgnoreProperties(ignoreUnknown=true)
+    @XmlRootElement
+    @XmlAccessorType(XmlAccessType.FIELD)
+    public static class ValidityInterval {
+        private final int days;
+        private final int hours;
+        private final int minutes;
+
+        public static int getValidityIntervalInMinutes(ValidityInterval interval) {
+            return interval != null ?
+                    (interval.getDays()*24 + interval.getHours())*60 + interval.getMinutes() : 0;
+        }
+
+        public ValidityInterval() {
+            this.days = 0;
+            this.hours = 0;
+            this.minutes = 0;
+        }
+        public ValidityInterval(int days, int hours, int minutes) {
+            this.days = days;
+            this.hours = hours;
+            this.minutes = minutes;
+        }
+        public int getDays() { return days; }
+        public int getHours() { return hours; }
+        public int getMinutes() { return minutes; }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("ValidityInterval={");
+
+            sb.append(" Interval={");
+            sb.append("days=").append(days);
+            sb.append(", hours=").append(hours);
+            sb.append(", minutes=").append(minutes);
+            sb.append(" }");
+
+            return sb.toString();
+        }
+    }
+
+    @JsonAutoDetect(fieldVisibility= JsonAutoDetect.Visibility.ANY)
+    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+    @JsonIgnoreProperties(ignoreUnknown=true)
+    @XmlRootElement
+    @XmlAccessorType(XmlAccessType.FIELD)
+    public static class RecurrenceSchedule {
+        static final String PERMITTED_SPECIAL_CHARACTERS = "*,-";
+        static final String PERMITTED_SPECIAL_CHARACTERS_FOR_MINUTES = ",";
+        public static final String WILDCARD = "*";
+
+        public enum ScheduleFieldSpec {
+            minute(0, 59, PERMITTED_SPECIAL_CHARACTERS_FOR_MINUTES),
+            hour(0, 23, PERMITTED_SPECIAL_CHARACTERS),
+            dayOfMonth(1, 31, PERMITTED_SPECIAL_CHARACTERS),
+            dayOfWeek(1, 7, PERMITTED_SPECIAL_CHARACTERS),
+            month(0, 11, PERMITTED_SPECIAL_CHARACTERS),
+            year(2017, 2100, PERMITTED_SPECIAL_CHARACTERS),
+            ;
+
+            public final int minimum;
+            public final int maximum;
+            public final String specialChars;
+
+            ScheduleFieldSpec(int minimum, int maximum, String specialChars) {
+                this.minimum = minimum;
+                this.maximum = maximum;
+                this.specialChars = specialChars;
+            }
+        }
+
+
+        private String minute;
+        private String hour;
+        private String dayOfMonth;
+        private String dayOfWeek;
+        private String month;
+        private String year;
+
+        public RecurrenceSchedule() {}
+
+        public RecurrenceSchedule(String minute, String hour, String dayOfMonth, String dayOfWeek, String month, String year) {
+            setMinute(minute);
+            setHour(hour);
+            setDayOfMonth(dayOfMonth);
+            setDayOfWeek(dayOfWeek);
+            setMonth(month);
+            setYear(year);
+        }
+        public String getMinute() { return minute;}
+        public String getHour() { return hour;}
+        public String getDayOfMonth() { return dayOfMonth;}
+        public String getDayOfWeek() { return dayOfWeek;}
+        public String getMonth() { return month;}
+        public String getYear() { return year;}
+
+        public void setMinute(String minute) { this.minute = minute;}
+        public void setHour(String hour) { this.hour = hour;}
+        public void setDayOfMonth(String dayOfMonth) { this.dayOfMonth = dayOfMonth;}
+        public void setDayOfWeek(String dayOfWeek) { this.dayOfWeek = dayOfWeek;}
+        public void setMonth(String month) { this.month = month;}
+        public void setYear(String year) { this.year = year;}
+
+        public void setFieldValue(ScheduleFieldSpec field, String value) {
+            switch (field) {
+                case minute:
+                    setMinute(value);
+                    break;
+                case hour:
+                    setHour(value);
+                    break;
+                case dayOfMonth:
+                    setDayOfMonth(value);
+                    break;
+                case dayOfWeek:
+                    setDayOfWeek(value);
+                    break;
+                case month:
+                    setMonth(value);
+                    break;
+                case year:
+                    setYear(value);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        public String getFieldValue(ScheduleFieldSpec field) {
+            switch (field) {
+                case minute:
+                    return getMinute();
+                case hour:
+                    return getHour();
+                case dayOfMonth:
+                    return getDayOfMonth();
+                case dayOfWeek:
+                    return getDayOfWeek();
+                case month:
+                    return getMonth();
+                case year:
+                    return getYear();
+                default:
+                    return null;
+            }
+        }
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(" Schedule={");
+            sb.append(" minute=").append(minute);
+            sb.append(", hour=").append(hour);
+            sb.append(", dayOfMonth=").append(dayOfMonth);
+            sb.append(", dayOfWeek=").append(dayOfWeek);
+            sb.append(", month=").append(month);
+            sb.append(", year=").append(year);
+            sb.append(" }");
+
+            return sb.toString();
+        }
+    }
+
+    private RecurrenceSchedule schedule;
+    private ValidityInterval interval;
+
+    public RangerValidityRecurrence() {
+    }
+
+    public RangerValidityRecurrence(RecurrenceSchedule schedule, ValidityInterval interval) {
+        setSchedule(schedule);
+        setInterval(interval);
+    }
+
+    public void setSchedule(RecurrenceSchedule schedule) { this.schedule = schedule;}
+
+    public void setInterval(ValidityInterval interval) { this.interval = interval; }
+
+    public RecurrenceSchedule getSchedule() { return schedule;}
+
+    public ValidityInterval getInterval() {
+        return interval;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{RangerValidityRecurrence= {");
+        sb.append(schedule).append(interval);
+        sb.append(" }");
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValiditySchedule.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValiditySchedule.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValiditySchedule.java
new file mode 100644
index 0000000..8fe3231
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerValiditySchedule.java
@@ -0,0 +1,93 @@
+/*
+ * 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.plugin.model;
+
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+@JsonAutoDetect(fieldVisibility=Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+
+public class RangerValiditySchedule {
+
+    private static final Log LOG = LogFactory.getLog(RangerValiditySchedule.class);
+
+    public static final String VALIDITY_SCHEDULE_DATE_STRING_SPECIFICATION = "yyyy/MM/dd HH:mm:ss";
+
+    private String startTime;
+    private String endTime;
+    private String timeZone;
+
+    private List<RangerValidityRecurrence> recurrences;
+
+    public RangerValiditySchedule(String startTime, String endTime, String timeZone, List<RangerValidityRecurrence> recurrences) {
+        setTimeZone(timeZone);
+        setStartTime(startTime);
+        setEndTime(endTime);
+        setRecurrences(recurrences);
+    }
+
+    public RangerValiditySchedule() {
+        this(null, null, null, null);
+    }
+
+    public String getTimeZone() { return timeZone; }
+    public String getStartTime() { return startTime;}
+    public String getEndTime() { return endTime;}
+    public List<RangerValidityRecurrence> getRecurrences() { return recurrences;}
+
+    public void setTimeZone(String timeZone) { this.timeZone = timeZone; }
+    public void setStartTime(String startTime) { this.startTime = startTime;}
+    public void setEndTime(String endTime) { this.endTime = endTime;}
+    public void setRecurrences(List<RangerValidityRecurrence> recurrences) { this.recurrences = recurrences == null ? new ArrayList<>() : recurrences;}
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("RangerValiditySchedule={");
+
+        sb.append(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", timeZone=").append(timeZone);
+
+        sb.append(", recurrences=").append(Arrays.toString(getRecurrences().toArray()));
+
+        sb.append("}");
+
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
index 95eeca7..4d2fa23 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
@@ -37,6 +37,7 @@ import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.model.RangerValiditySchedule;
 import org.apache.ranger.plugin.store.ServiceStore;
 
 public class RangerPolicyValidator extends RangerValidator {
@@ -123,6 +124,19 @@ public class RangerPolicyValidator extends RangerValidator {
 				.build());
 			valid = false;
 		} else {
+			Integer priority = policy.getPolicyPriority();
+			if (priority != null) {
+				if (priority < RangerPolicy.POLICY_PRIORITY_NORMAL || priority > RangerPolicy.POLICY_PRIORITY_OVERRIDE) {
+					ValidationErrorCode error = ValidationErrorCode.POLICY_VALIDATION_ERR_POLICY_INVALID_PRIORITY;
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("policyPriority")
+							.isSemanticallyIncorrect()
+							.becauseOf(error.getMessage("out of range"))
+							.errorCode(error.getErrorCode())
+							.build());
+					valid = false;
+				}
+			}
 			Long id = policy.getId();
 			RangerPolicy existingPolicy = null;
 
@@ -306,6 +320,7 @@ public class RangerPolicyValidator extends RangerValidator {
 			}
 
 			if (serviceNameValid) { // resource checks can't be done meaningfully otherwise
+				valid = isValidValiditySchedule(policy, failures, action) && valid;
 				valid = isValidResources(policy, failures, action, isAdmin, serviceDef) && valid;
 				valid = isValidAccessTypeDef(policy, failures, action, isAdmin, serviceDef) && valid;
 			}
@@ -413,7 +428,41 @@ public class RangerPolicyValidator extends RangerValidator {
 		}
 		return valid;
 	}
-	
+
+	boolean isValidValiditySchedule(RangerPolicy policy, final List<ValidationFailureDetails> failures, Action action) {
+
+		boolean valid = true;
+		if (LOG.isDebugEnabled()) {
+			LOG.debug(String.format("==> RangerPolicyValidator.isValidValiditySchedule(%s, %s, %s)", policy, failures, action));
+		}
+		List<RangerValiditySchedule> validitySchedules = policy.getValiditySchedules();
+		List<RangerValiditySchedule> normalizedValiditySchedules = null;
+
+		for (RangerValiditySchedule entry : validitySchedules) {
+			RangerValidityScheduleValidator validator = new RangerValidityScheduleValidator(entry);
+
+			RangerValiditySchedule normalizedValiditySchedule = validator.validate(failures);
+			if (normalizedValiditySchedule == null) {
+				valid = false;
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("Invalid Validity-Schedule:[" + entry +"]");
+				}
+			} else {
+				if (normalizedValiditySchedules == null) {
+					normalizedValiditySchedules = new ArrayList<>();
+				}
+				normalizedValiditySchedules.add(normalizedValiditySchedule);
+			}
+		}
+		if (valid && CollectionUtils.isNotEmpty(normalizedValiditySchedules)) {
+			policy.setValiditySchedules(normalizedValiditySchedules);
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug(String.format("<== RangerPolicyValidator.isValidValiditySchedule(%s, %s, %s): %s", policy, failures, action, valid));
+		}
+		return valid;
+	}
+
 	boolean isPolicyResourceUnique(RangerPolicy policy, final List<ValidationFailureDetails> failures, Action action) {
 		
 		if(LOG.isDebugEnabled()) {

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidator.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidator.java
index 509c188..55973f5 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidator.java
@@ -96,7 +96,7 @@ public abstract class RangerValidator {
 		return false;
 	}
 
-	String serializeFailures(List<ValidationFailureDetails> failures) {
+	public static String serializeFailures(List<ValidationFailureDetails> failures) {
 		if(LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerValidator.getFailureMessage()");
 		}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidityScheduleValidator.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidityScheduleValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidityScheduleValidator.java
new file mode 100644
index 0000000..63e8bc0
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerValidityScheduleValidator.java
@@ -0,0 +1,480 @@
+/*
+ * 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.plugin.model.validation;
+
+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 java.io.Serializable;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+
+import org.apache.ranger.plugin.model.RangerValidityRecurrence;
+import org.apache.ranger.plugin.model.RangerValidityRecurrence.RecurrenceSchedule;
+import org.apache.ranger.plugin.model.RangerValiditySchedule;
+
+import javax.annotation.Nonnull;
+
+public class RangerValidityScheduleValidator {
+    private static final Log LOG = LogFactory.getLog(RangerValidityScheduleValidator.class);
+
+    private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
+        @Override
+        protected DateFormat initialValue() {
+            return new SimpleDateFormat(RangerValiditySchedule.VALIDITY_SCHEDULE_DATE_STRING_SPECIFICATION);
+        }
+    };
+
+    private static final Set<String> validTimeZoneIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
+
+    private final RangerValiditySchedule validitySchedule;
+    private Date                         startTime;
+    private Date                         endTime;
+    private RecurrenceSchedule           validityPeriodEstimator;
+    private RangerValiditySchedule       normalizedValiditySchedule;
+
+    public RangerValidityScheduleValidator(@Nonnull RangerValiditySchedule validitySchedule) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerValidityScheduleValidator:: " + validitySchedule);
+        }
+
+        this.validitySchedule = validitySchedule;
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RangerValidityScheduleValidator:: " + validitySchedule);
+        }
+    }
+
+    public RangerValiditySchedule validate(List<ValidationFailureDetails> validationFailures) {
+        RangerValiditySchedule ret = null;
+
+        if (StringUtils.isEmpty(validitySchedule.getStartTime()) && StringUtils.isEmpty(validitySchedule.getEndTime()) && CollectionUtils.isEmpty(validitySchedule.getRecurrences())) {
+            validationFailures.add(new ValidationFailureDetails(0, "startTime,endTime,recurrences", "", true, true, false, "empty values"));
+        } else {
+
+            if (validitySchedule.getStartTime() != null) {
+                try {
+                    startTime = DATE_FORMATTER.get().parse(validitySchedule.getStartTime());
+                } catch (ParseException exception) {
+                    LOG.error("Error parsing startTime:[" + validitySchedule.getStartTime() + "]", exception);
+                    validationFailures.add(new ValidationFailureDetails(0, "startTime", "", true, true, false, "invalid value"));
+                }
+            } else {
+                startTime = new Date();
+            }
+
+            if (validitySchedule.getEndTime() != null) {
+                try {
+                    endTime = DATE_FORMATTER.get().parse(validitySchedule.getEndTime());
+                } catch (ParseException exception) {
+                    LOG.error("Error parsing endTime:[" + validitySchedule.getEndTime() + "]", exception);
+                    validationFailures.add(new ValidationFailureDetails(0, "endTime", "", true, true, false, "invalid value"));
+                }
+            } else {
+                endTime = new Date(Long.MAX_VALUE);
+            }
+
+            if (startTime != null && endTime != null) {
+                validityPeriodEstimator = new RangerValidityRecurrence.RecurrenceSchedule();
+                normalizedValiditySchedule = new RangerValiditySchedule();
+
+                boolean isValid = validateTimeRangeSpec(validationFailures);
+
+                if (isValid) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("validityPeriodEstimator:[" + validityPeriodEstimator + "]");
+                    }
+
+                    normalizedValiditySchedule.setStartTime(validitySchedule.getStartTime());
+                    normalizedValiditySchedule.setEndTime(validitySchedule.getEndTime());
+                    normalizedValiditySchedule.setTimeZone(validitySchedule.getTimeZone());
+
+                    ret = normalizedValiditySchedule;
+                } else {
+                    normalizedValiditySchedule = null;
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    private boolean validateTimeRangeSpec(List<ValidationFailureDetails> validationFailures) {
+        boolean ret;
+        if (startTime.getTime() >= endTime.getTime()) {
+            validationFailures.add(new ValidationFailureDetails(0, "startTime", "", false, true, false, "endTime is not later than startTime"));
+            ret = false;
+        } else {
+            ret = true;
+        }
+        ret = validateTimeZone(validitySchedule.getTimeZone(), validationFailures) && ret;
+
+        for (RangerValidityRecurrence recurrence : validitySchedule.getRecurrences()) {
+            ret = validateValidityInterval(recurrence, validationFailures) && ret;
+
+            if (RangerValidityRecurrence.ValidityInterval.getValidityIntervalInMinutes(recurrence.getInterval()) > 0) {
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute, validationFailures) && ret;
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour, validationFailures) && ret;
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth, validationFailures) && ret;
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek, validationFailures) && ret;
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month, validationFailures) && ret;
+                ret = validateFieldSpec(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.year, validationFailures) && ret;
+                ret = ret && validateIntervalDuration(recurrence, validationFailures);
+
+                if (ret) {
+                    RangerValidityRecurrence.RecurrenceSchedule schedule = new RangerValidityRecurrence.RecurrenceSchedule(getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute), getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour),
+                            getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth), getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek),
+                            getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month), getNormalizedValue(recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.year));
+                    RangerValidityRecurrence normalizedRecurrence = new RangerValidityRecurrence(schedule, recurrence.getInterval());
+                    normalizedValiditySchedule.getRecurrences().add(normalizedRecurrence);
+
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    private boolean validateTimeZone(String timeZone, List<ValidationFailureDetails> validationFailures) {
+        boolean ret = !StringUtils.isNotBlank(timeZone) || validTimeZoneIds.contains(timeZone);
+
+        if (!ret) {
+            validationFailures.add(new ValidationFailureDetails(0, "timeZone", "", false, true, false, "invalid timeZone"));
+        }
+        return ret;
+    }
+
+    private boolean validateValidityInterval(RangerValidityRecurrence recurrence, List<ValidationFailureDetails> validationFailures) {
+        boolean ret = true;
+        RangerValidityRecurrence.ValidityInterval validityInterval = recurrence.getInterval();
+        if (validityInterval != null) {
+            if (validityInterval.getDays() < 0
+                    || (validityInterval.getHours() < 0 || validityInterval.getHours() > 23)
+                    || (validityInterval.getMinutes() < 0 || validityInterval.getMinutes() > 59)) {
+                validationFailures.add(new ValidationFailureDetails(0, "interval", "", false, true, false, "invalid interval"));
+                ret = false;
+            }
+        }
+        int validityIntervalInMinutes = RangerValidityRecurrence.ValidityInterval.getValidityIntervalInMinutes(validityInterval);
+        if (validityIntervalInMinutes > 0) {
+            if (StringUtils.isBlank(recurrence.getSchedule().getDayOfMonth()) && StringUtils.isBlank(recurrence.getSchedule().getDayOfWeek())) {
+                validationFailures.add(new ValidationFailureDetails(0, "validitySchedule", "", false, true, false, "empty dayOfMonth and dayOfWeek"));
+                ret = false;
+            }
+        }
+        return ret;
+    }
+
+    private boolean validateFieldSpec(RangerValidityRecurrence recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec field, List<ValidationFailureDetails> validationFailures) {
+        boolean ret = true;
+
+        String fieldValue = recurrence.getSchedule().getFieldValue(field);
+        if (StringUtils.isBlank(fieldValue)) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("No value provided for [" + field + "]");
+            }
+            if (StringUtils.equals(field.name(), RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek.name())
+                    || StringUtils.equals(field.name(), RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth.name())) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Allow blank value for dayOfWeek or dayOfMonth here. Check for both being null is done elsewhere.");
+                }
+            } else {
+                validationFailures.add(new ValidationFailureDetails(0, field.toString(), "", false, true, false, "No value provided"));
+            }
+        }
+        ret = validateCharacters(fieldValue, field.specialChars);
+
+        if (!ret) {
+            validationFailures.add(new ValidationFailureDetails(0, field.toString(), "", false, true, false, "invalid character(s)"));
+        } else {
+            // Valid month values in java.util.Date are from 1-12, in java.util.Calendar from 0 to 11
+            // Internally we use Calendar values for validation and evaluation
+            int minimum = field == RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month ? field.minimum + 1 : field.minimum;
+            int maximum = field == RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month ? field.maximum + 1 : field.maximum;
+            ret = validateRanges(recurrence, field, minimum, maximum, validationFailures);
+        }
+        return ret;
+    }
+
+    private boolean validateCharacters(String str, String permittedCharacters) {
+        boolean ret = true;
+        if (StringUtils.isNotBlank(str)) {
+            char[] chars = str.toCharArray();
+            for (char c : chars) {
+                if (!(Character.isDigit(c) || Character.isWhitespace(c) || StringUtils.contains(permittedCharacters, c))) {
+                    ret = false;
+                    break;
+                }
+            }
+        }
+        return ret;
+    }
+
+    private boolean validateIntervalDuration(RangerValidityRecurrence recurrence, List<ValidationFailureDetails> validationFailures) {
+        boolean ret = true;
+
+        if (!validationFailures.isEmpty() || validityPeriodEstimator == null) {
+            ret = false;
+        } else {
+            int minSchedulingInterval = 1; // In minutes
+
+            String minutes = validityPeriodEstimator.getFieldValue(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute);
+            if (!StringUtils.equals(minutes, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                minSchedulingInterval = StringUtils.isBlank(minutes) ? RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum + 1 : Integer.valueOf(minutes);
+
+                if (minSchedulingInterval == RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum + 1) {
+                    String hours = validityPeriodEstimator.getFieldValue(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour);
+                    if (!StringUtils.equals(hours, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                        int hour = StringUtils.isBlank(hours) ? RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour.maximum + 1 :Integer.valueOf(hours);
+                        minSchedulingInterval = hour * (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum+1);
+
+                        if (hour == RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour.maximum + 1) {
+                            String dayOfMonths = validityPeriodEstimator.getFieldValue(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth);
+                            String dayOfWeeks = validityPeriodEstimator.getFieldValue(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek);
+
+                            int dayOfMonth = 1, dayOfWeek = 1;
+                            if (!StringUtils.equals(dayOfMonths, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                                dayOfMonth = StringUtils.isBlank(dayOfMonths) ? RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth.maximum + 1 : Integer.valueOf(dayOfMonths);
+                            }
+                            if (!StringUtils.equals(dayOfWeeks, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                                dayOfWeek = StringUtils.isBlank(dayOfWeeks) ? RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek.maximum + 1 : Integer.valueOf(dayOfWeeks);
+                            }
+                            if (!StringUtils.equals(dayOfMonths, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD) || !StringUtils.equals(dayOfWeeks, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                                int minDays = dayOfMonth > dayOfWeek ? dayOfWeek : dayOfMonth;
+                                minSchedulingInterval = minDays*(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour.maximum+1)*(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum+1);
+
+                                if (dayOfMonth == (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfMonth.maximum+1) && dayOfWeek == (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.dayOfWeek.maximum+1)) {
+                                    String months = validityPeriodEstimator.getFieldValue(RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month);
+                                    if (!StringUtils.equals(months, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                                        int month = StringUtils.isBlank(months) ? RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month.maximum + 1 :Integer.valueOf(months);
+                                        minSchedulingInterval = month * 28 * (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour.maximum + 1) * (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum + 1);
+
+                                        if (month == RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.month.maximum + 1) {
+                                            // Maximum interval is 1 year
+                                            minSchedulingInterval = 365 * (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.hour.maximum + 1) * (RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec.minute.maximum + 1);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (RangerValidityRecurrence.ValidityInterval.getValidityIntervalInMinutes(recurrence.getInterval()) > minSchedulingInterval) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.warn("Specified scheduling interval:" + RangerValidityRecurrence.ValidityInterval.getValidityIntervalInMinutes(recurrence.getInterval()) + " minutes] is more than minimum possible scheduling interval:[" + minSchedulingInterval + " minutes].");
+                    LOG.warn("This may turn this (expected to be temporary) policy into effectively permanent policy.");
+                }
+            }
+        }
+        return ret;
+    }
+
+    private boolean validateRanges(RangerValidityRecurrence recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec field, int minValidValue, int maxValidValue, List<ValidationFailureDetails> validationFailures) {
+        boolean ret = true;
+
+        String value = null;
+        String fieldName = field.toString();
+
+        String noWhiteSpace = StringUtils.deleteWhitespace(recurrence.getSchedule().getFieldValue(field));
+        String[] specs = StringUtils.split(noWhiteSpace, ",");
+        class Range {
+            private int lower;
+            private int upper;
+            private Range(int lower, int upper) {
+                this.lower = lower;
+                this.upper = upper;
+            }
+        }
+        class RangeComparator implements Comparator<Range>, Serializable {
+            @Override
+            public int compare(Range me, Range other) {
+                int result;
+                result = Integer.compare(me.lower, other.lower);
+                if (result == 0) {
+                    result = Integer.compare(me.upper, other.upper);
+                }
+                return result;
+            }
+        }
+
+        List<Range> rangeOfValues = new ArrayList<>();
+
+        List<Integer> values = new ArrayList<>();
+
+        for (String spec : specs) {
+
+            if (StringUtils.isNotEmpty(spec)) {
+                // Range
+                if (spec.startsWith("-") || spec.endsWith("-")) {
+                    validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect range spec"));
+                    ret = false;
+                } else {
+                    String[] ranges = StringUtils.split(spec, "-");
+                    if (ranges.length > 2) {
+                        validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect range spec"));
+                        ret = false;
+                    } else if (ranges.length == 2) {
+                        int val1 = minValidValue, val2 = maxValidValue;
+                        if (!StringUtils.equals(ranges[0], RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                            val1 = Integer.valueOf(ranges[0]);
+                            if (val1 < minValidValue || val1 > maxValidValue) {
+                                validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect lower range value"));
+                                ret = false;
+                            }
+                        } else {
+                            value = RangerValidityRecurrence.RecurrenceSchedule.WILDCARD;
+                        }
+                        if (!StringUtils.equals(ranges[1], RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                            val2 = Integer.valueOf(ranges[1]);
+                            if (val1 < minValidValue || val2 > maxValidValue) {
+                                validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect upper range value"));
+                                ret = false;
+                            }
+                        } else {
+                            value = RangerValidityRecurrence.RecurrenceSchedule.WILDCARD;
+                        }
+                        if (ret) {
+                            if (val1 >= val2) {
+                                validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect range"));
+                                ret = false;
+                            } else {
+                                value = RangerValidityRecurrence.RecurrenceSchedule.WILDCARD;
+                                for (Range range : rangeOfValues) {
+                                    if (range.lower == val1 || range.upper == val2) {
+                                        validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "duplicate range"));
+                                        ret = false;
+                                        break;
+                                    }
+                                }
+                                if (ret) {
+                                    rangeOfValues.add(new Range(val1, val2));
+                                }
+                            }
+                        }
+                    } else if (ranges.length == 1) {
+                        if (!StringUtils.equals(ranges[0], RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                            int val = Integer.valueOf(ranges[0]);
+                            if (val < minValidValue || val > maxValidValue) {
+                                validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "incorrect value"));
+                                ret = false;
+                            } else {
+                                if (!StringUtils.equals(value, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+                                    values.add(Integer.valueOf(ranges[0]));
+                                }
+                            }
+                        } else {
+                            value = RangerValidityRecurrence.RecurrenceSchedule.WILDCARD;
+                        }
+                    } else {
+                        ret = false;
+                    }
+                }
+            }
+        }
+        //if (ret) {
+            if (CollectionUtils.isNotEmpty(rangeOfValues)) {
+                rangeOfValues.sort( new RangeComparator());
+            }
+            for (int i = 0; i < rangeOfValues.size(); i++) {
+                Range range = rangeOfValues.get(i);
+                int upper = range.upper;
+                for (int j = i+1; j < rangeOfValues.size(); j++) {
+                    Range r = rangeOfValues.get(j);
+                    if (upper < r.upper) {
+                        validationFailures.add(new ValidationFailureDetails(0, fieldName, "", false, true, false, "overlapping range value"));
+                        ret = false;
+                    }
+                }
+            }
+        //}
+        if (ret) {
+            if (!StringUtils.equals(value, RangerValidityRecurrence.RecurrenceSchedule.WILDCARD)) {
+
+                int minDiff = (values.size() <= 1) ?  maxValidValue + 1 : Integer.MAX_VALUE;
+
+                if (values.size() > 1) {
+                    Collections.sort(values);
+                    for (int i = 0; i < values.size() - 1; i++) {
+                        int diff = values.get(i + 1) - values.get(i);
+                        if (diff < minDiff) {
+                            minDiff = diff;
+                        }
+                        int firstLastDiff = values.get(0) + (maxValidValue - minValidValue + 1) - values.get(values.size() - 1);
+
+                        if (minDiff > firstLastDiff) {
+                            minDiff = firstLastDiff;
+                        }
+                    }
+                }
+                if (values.size() > 0) {
+                    value = Integer.toString(minDiff);
+                }
+            }
+            validityPeriodEstimator.setFieldValue(field, value);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Set " + field + " to " + value);
+            }
+        }
+        return ret;
+    }
+
+    private String getNormalizedValue(RangerValidityRecurrence recurrence, RangerValidityRecurrence.RecurrenceSchedule.ScheduleFieldSpec field) {
+        String ret = null;
+
+        if (RangerValidityRecurrence.ValidityInterval.getValidityIntervalInMinutes(recurrence.getInterval()) > 0) {
+            String noWhiteSpace = StringUtils.deleteWhitespace(recurrence.getSchedule().getFieldValue(field));
+            String[] specs = StringUtils.split(noWhiteSpace, ",");
+
+            List<String> values = new ArrayList<>();
+
+            for (String spec : specs) {
+                if (StringUtils.isNotBlank(spec)) {
+                    values.add(spec);
+                }
+            }
+            if (values.size() > 0) {
+                Collections.sort(values);
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < values.size(); i++) {
+                    if (i != 0) {
+                        sb.append(",");
+                    }
+                    sb.append(values.get(i));
+                }
+                ret = sb.toString();
+            }
+        }
+        return ret;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEvaluatorForTag.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEvaluatorForTag.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEvaluatorForTag.java
index 1aad049..1d961a1 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEvaluatorForTag.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEvaluatorForTag.java
@@ -26,33 +26,36 @@ import java.io.Serializable;
 import java.util.Comparator;
 
 public class PolicyEvaluatorForTag {
-    private final RangerPolicyEvaluator evaluator;
-    private final RangerTagForEval      tag;
-
-    PolicyEvaluatorForTag(RangerPolicyEvaluator evaluator, RangerTagForEval tag) {
-        this.evaluator = evaluator;
-        this.tag       = tag;
-    }
-
-    RangerPolicyEvaluator getEvaluator() {
-        return evaluator;
-    }
-
-    RangerTagForEval getTag() {
-        return tag;
-    }
-
-    public static class PolicyNameComparator implements Comparator<PolicyEvaluatorForTag>, Serializable {
-        @Override
-        public int compare(PolicyEvaluatorForTag me, PolicyEvaluatorForTag other) {
-            return me.getEvaluator().getPolicy().getName().compareTo(other.getEvaluator().getPolicy().getName());
-        }
-    }
-
-    public static class PolicyEvalOrderComparator implements Comparator<PolicyEvaluatorForTag>, Serializable {
-        @Override
-        public int compare(PolicyEvaluatorForTag me, PolicyEvaluatorForTag other) {
-            return RangerPolicyEvaluator.EVAL_ORDER_COMPARATOR.compare(me.getEvaluator(), other.getEvaluator());
-        }
-    }
+	public static final Comparator<PolicyEvaluatorForTag> EVAL_ORDER_COMPARATOR = new PolicyEvalOrderComparator();
+	public static final Comparator<PolicyEvaluatorForTag> NAME_COMPARATOR       = new PolicyNameComparator();
+
+	private final RangerPolicyEvaluator evaluator;
+	private final RangerTagForEval      tag;
+
+	PolicyEvaluatorForTag(RangerPolicyEvaluator evaluator, RangerTagForEval tag) {
+		this.evaluator = evaluator;
+		this.tag       = tag;
+	}
+
+	RangerPolicyEvaluator getEvaluator() {
+		return evaluator;
+	}
+
+	RangerTagForEval getTag() {
+		return tag;
+	}
+
+	static class PolicyNameComparator implements Comparator<PolicyEvaluatorForTag>, Serializable {
+		@Override
+		public int compare(PolicyEvaluatorForTag me, PolicyEvaluatorForTag other) {
+			return RangerPolicyEvaluator.NAME_COMPARATOR.compare(me.getEvaluator(), other.getEvaluator());
+		}
+	}
+
+	static class PolicyEvalOrderComparator implements Comparator<PolicyEvaluatorForTag>, Serializable {
+		@Override
+		public int compare(PolicyEvaluatorForTag me, PolicyEvaluatorForTag other) {
+			return RangerPolicyEvaluator.EVAL_ORDER_COMPARATOR.compare(me.getEvaluator(), other.getEvaluator());
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/ranger/blob/844315cd/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
index 1b01ea4..8e7844f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java
@@ -45,6 +45,7 @@ public class RangerAccessResult {
 	private boolean  isAudited;
 	private long     auditPolicyId  = -1;
 	private long     policyId  = -1;
+	private int      policyPriority;
 	private long     evaluatedPoliciesCount;
 	private String   reason;
 	private Map<String, Object> additionalInfo;
@@ -60,6 +61,7 @@ public class RangerAccessResult {
 		this.isAudited   = false;
 		this.auditPolicyId = -1;
 		this.policyId    = -1;
+		this.policyPriority = RangerPolicy.POLICY_PRIORITY_NORMAL;
 		this.evaluatedPoliciesCount = 0;
 		this.reason      = null;
 	}
@@ -68,6 +70,7 @@ public class RangerAccessResult {
 		this.isAccessDetermined = other.getIsAccessDetermined();
 		this.isAllowed   = other.getIsAllowed();
 		this.policyId    = other.getPolicyId();
+		this.policyPriority = other.getPolicyPriority();
 		this.evaluatedPoliciesCount = other.evaluatedPoliciesCount;
 		this.reason      = other.getReason();
 		this.additionalInfo = other.additionalInfo == null ? new HashMap<String, Object>() : new HashMap<>(other.additionalInfo);
@@ -123,6 +126,9 @@ public class RangerAccessResult {
 
 		this.isAllowed = isAllowed;
 	}
+	public int getPolicyPriority() { return policyPriority;}
+
+	public void setPolicyPriority(int policyPriority) { this.policyPriority = policyPriority; }
 
 	/**
 	 * @param reason the reason to set


Mime
View raw message