Replace validation code with annotations
[policy/xacml-pdp.git] / applications / guard / src / main / java / org / onap / policy / xacml / pdp / application / guard / GuardTranslator.java
index 4365cad..d606cc2 100644 (file)
@@ -2,7 +2,8 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2020 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,9 +30,15 @@ import com.att.research.xacml.api.Request;
 import com.att.research.xacml.api.Response;
 import com.att.research.xacml.api.Result;
 import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
 import com.att.research.xacml.std.annotations.RequestParser;
+import com.google.gson.annotations.SerializedName;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
+import lombok.Getter;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
@@ -44,6 +51,11 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinitionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableReferenceType;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 import org.onap.policy.models.decisions.concepts.DecisionResponse;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
@@ -85,9 +97,26 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     //
     public static final String FIELD_BLACKLIST = "blacklist";
 
+    //
+    // filter property fields
+    //
+    public static final String FIELD_FILTER_WHITELIST = "whitelist";
+    public static final String FIELD_FILTER_ALGORITHM = "algorithm";
+    public static final String FIELD_FILTER_FILTERS = "filters";
+    public static final String FIELD_FILTER_FIELD = "field";
+    public static final String FIELD_FILTER_FUNCTION = "function";
+    public static final String FIELD_FILTER_FILTER = "filter";
+    public static final String FIELD_FILTER_BLACKLIST = "blacklist";
+
     public static final String POLICYTYPE_FREQUENCY = "onap.policies.controlloop.guard.common.FrequencyLimiter";
     public static final String POLICYTYPE_MINMAX = "onap.policies.controlloop.guard.common.MinMax";
     public static final String POLICYTYPE_BLACKLIST = "onap.policies.controlloop.guard.common.Blacklist";
+    public static final String POLICYTYPE_FILTER = "onap.policies.controlloop.guard.common.Filter";
+
+    //
+    // Variable definitions
+    //
+    private static final String VARIABLE_TIMEINRANGE = "timeInRange";
 
     public GuardTranslator() {
         super();
@@ -96,7 +125,8 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     /**
      * Convert the policy.
      */
-    public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
+    @Override
+    public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
         //
         // Policy name should be at the root
         //
@@ -104,7 +134,7 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         //
         // Set it as the policy ID
         //
-        PolicyType newPolicyType = new PolicyType();
+        var newPolicyType = new PolicyType();
         newPolicyType.setPolicyId(policyName);
         //
         // Optional description
@@ -115,6 +145,12 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         //
         this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
         //
+        // There should be properties metadata section
+        //
+        if (toscaPolicy.getProperties() == null) {
+            throw new ToscaPolicyConversionException("no properties specified on guard policy: " + policyName);
+        }
+        //
         // Generate the TargetType - add true if not blacklist
         //
         newPolicyType.setTarget(this.generateTargetType(toscaPolicy.getProperties(),
@@ -131,34 +167,80 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         } else if (POLICYTYPE_BLACKLIST.equals(toscaPolicy.getType())) {
             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
             generateBlacklistRules(toscaPolicy, policyName, newPolicyType);
+        } else if (POLICYTYPE_FILTER.equals(toscaPolicy.getType())) {
+            newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
+            generateFilterRules(toscaPolicy, policyName, newPolicyType);
         } else {
             throw new ToscaPolicyConversionException("Unknown guard policy type " + toscaPolicy.getType());
         }
+        //
+        // Add in our variable definition
+        //
+        VariableReferenceType variable = this.createTimeRangeVariable(toscaPolicy.getProperties(), newPolicyType);
+        if (variable != null) {
+            //
+            // Update all the rules to have conditions for this variable
+            //
+            this.addVariableToConditionTypes(variable, newPolicyType);
+        }
         return newPolicyType;
     }
 
+    /**
+     * This method iterates through all the existing rules, adding in a conditionType that will test
+     * whether the Variable is true or false. Any existing ConditionType will be updated to AND with the
+     * Variable.
+     *
+     * @param variable VariableDefinitionType to add
+     * @param newPolicyType PolicyType that will be updated
+     */
+    private void addVariableToConditionTypes(VariableReferenceType variable,
+            PolicyType newPolicyType) {
+        //
+        // Iterate through the rules
+        //
+        for (Object objectType : newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition()) {
+            if (objectType instanceof RuleType) {
+                RuleType rule = (RuleType) objectType;
+                if (rule.getCondition() == null) {
+                    //
+                    // No condition already, just create and add a new one
+                    //
+                    var condition = new ConditionType();
+                    condition.setExpression(new ObjectFactory().createVariableReference(variable));
+                    rule.setCondition(condition);
+                } else {
+                    //
+                    // Need to create a new ConditionType that treats all the expressions as an AND
+                    // with the Variable.
+                    //
+                    rule.setCondition(ToscaPolicyTranslatorUtils.addVariableToCondition(rule.getCondition(), variable,
+                            XACML3.ID_FUNCTION_AND));
+                }
+            }
+        }
+    }
+
     /**
      * Convert Request.
      */
-    public Request convertRequest(DecisionRequest request) {
+    @Override
+    public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
         LOGGER.info("Converting Request {}", request);
         try {
             return RequestParser.parseRequest(GuardPolicyRequest.createInstance(request));
         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
-            LOGGER.error("Failed to convert DecisionRequest", e);
+            throw new ToscaPolicyConversionException("Failed to convert DecisionRequest", e);
         }
-        //
-        // TODO throw exception
-        //
-        return null;
     }
 
     /**
      * Convert response.
      */
+    @Override
     public DecisionResponse convertResponse(Response xacmlResponse) {
         LOGGER.info("Converting Response {}", xacmlResponse);
-        DecisionResponse decisionResponse = new DecisionResponse();
+        var decisionResponse = new DecisionResponse();
         //
         // Iterate through all the results
         //
@@ -217,29 +299,31 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     protected TargetType generateTargetType(Map<String, Object> properties, boolean addTargets)
             throws ToscaPolicyConversionException {
         //
+        // Decode the definition from the policy's properties
+        //
+        TargetTypeDefinition targetTypeDef =
+                        ToscaPolicyTranslatorUtils.decodeProperties(properties, TargetTypeDefinition.class);
+        //
         // Go through potential properties
         //
-        AllOfType allOf = new AllOfType();
-        if (properties.containsKey(FIELD_ACTOR)) {
-            addMatch(allOf, properties.get(FIELD_ACTOR), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
+        var allOf = new AllOfType();
+        if (targetTypeDef.getActor() != null) {
+            addMatch(allOf, targetTypeDef.getActor(), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
         }
-        if (properties.containsKey(FIELD_OPERATION)) {
-            addMatch(allOf, properties.get(FIELD_OPERATION), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
+        if (targetTypeDef.getOperation() != null) {
+            addMatch(allOf, targetTypeDef.getOperation(), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
         }
-        if (addTargets && properties.containsKey(FIELD_TARGET)) {
-            addMatch(allOf, properties.get(FIELD_TARGET), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
+        if (addTargets && targetTypeDef.getTarget() != null) {
+            addMatch(allOf, targetTypeDef.getTarget(), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
         }
-        if (properties.containsKey(FIELD_CONTROLLOOP)) {
-            addMatch(allOf, properties.get(FIELD_CONTROLLOOP), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME);
-        }
-        if (properties.containsKey(FIELD_TIMERANGE)) {
-            addTimeRangeMatch(allOf, properties.get(FIELD_TIMERANGE));
+        if (targetTypeDef.getId() != null) {
+            addMatch(allOf, targetTypeDef.getId(), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME);
         }
         //
         // Create target
         //
-        TargetType target = new TargetType();
-        AnyOfType anyOf = new AnyOfType();
+        var target = new TargetType();
+        var anyOf = new AnyOfType();
         anyOf.getAllOf().add(allOf);
         target.getAnyOf().add(anyOf);
         return target;
@@ -257,7 +341,7 @@ public class GuardTranslator implements ToscaPolicyTranslator {
                 //
                 // Exact match
                 //
-                MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                     XACML3.ID_FUNCTION_STRING_EQUAL,
                     value,
                     XACML3.ID_DATATYPE_STRING,
@@ -270,7 +354,7 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         }
         if (value instanceof Collection) {
             ((Collection<String>) value).forEach(val -> {
-                MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                         XACML3.ID_FUNCTION_STRING_EQUAL,
                         val,
                         XACML3.ID_DATATYPE_STRING,
@@ -283,25 +367,21 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         return allOf;
     }
 
-    @SuppressWarnings("rawtypes")
-    protected void addTimeRangeMatch(AllOfType allOf, Object timeRange)
+    protected void addTimeRangeMatch(AllOfType allOf, TimeRange timeRange)
             throws ToscaPolicyConversionException {
-        if (! (timeRange instanceof Map)) {
-            throw new ToscaPolicyConversionException("timeRange is not a map object " + timeRange.getClass());
-        }
 
-        MatchType matchStart = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+        var matchStart = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                 XACML3.ID_FUNCTION_TIME_GREATER_THAN_OR_EQUAL,
-                ((Map) timeRange).get("start_time").toString(),
+                timeRange.getStartTime(),
                 XACML3.ID_DATATYPE_TIME,
                 XACML3.ID_ENVIRONMENT_CURRENT_TIME,
-                XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+                XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT);
 
         allOf.getMatch().add(matchStart);
 
-        MatchType matchEnd = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+        var matchEnd = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                 XACML3.ID_FUNCTION_TIME_LESS_THAN_OR_EQUAL,
-                ((Map) timeRange).get("end_time").toString(),
+                timeRange.getEndTime(),
                 XACML3.ID_DATATYPE_TIME,
                 XACML3.ID_ENVIRONMENT_CURRENT_TIME,
                 XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT);
@@ -309,49 +389,97 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         allOf.getMatch().add(matchEnd);
     }
 
-    protected void generateFrequencyRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
+    protected VariableReferenceType createTimeRangeVariable(Map<String, Object> properties, PolicyType newPolicyType)
             throws ToscaPolicyConversionException {
         //
-        // We must have the limit
+        // Decode the definition from the policy's properties
         //
-        if (! toscaPolicy.getProperties().containsKey(FIELD_LIMIT)) {
-            throw new ToscaPolicyConversionException("Missing property limit");
+        TimeRangeDefinition timeRangeDef =
+                        ToscaPolicyTranslatorUtils.decodeProperties(properties, TimeRangeDefinition.class);
+        TimeRange timeRange = timeRangeDef.getTimeRange();
+        if (timeRange == null) {
+            return null;
         }
         //
-        // See if its possible to generate a count
+        // Should also be parseable as an ISO8601 timestamp
+        //
+        var startTimeObject = parseTimestamp(timeRange.getStartTime());
+        var endTimeObject = parseTimestamp(timeRange.getEndTime());
         //
-        Integer limit = ToscaPolicyTranslatorUtils.parseInteger(
-                toscaPolicy.getProperties().get(FIELD_LIMIT).toString());
-        if (limit == null) {
-            throw new ToscaPolicyConversionException("Missing limit value");
+        // They should be the same object types. We cannot establish a range
+        // between an OffsetDateTime and an OffsetTime
+        //
+        if (! startTimeObject.getClass().equals(endTimeObject.getClass())) {
+            throw new ToscaPolicyConversionException("start_time and end_time class types do not match");
         }
-        String timeWindow = null;
-        if (toscaPolicy.getProperties().containsKey(FIELD_TIMEWINDOW)) {
-            Integer intTimeWindow = ToscaPolicyTranslatorUtils.parseInteger(
-                    toscaPolicy.getProperties().get(FIELD_TIMEWINDOW).toString());
-            if (intTimeWindow == null) {
-                throw new ToscaPolicyConversionException("timeWindow is not an integer");
-            }
-            timeWindow = intTimeWindow.toString();
+        //
+        // Create the inner timeInRange ApplyType
+        //
+        ApplyType timeInRange = ToscaPolicyTranslatorUtils.generateTimeInRange(timeRange.getStartTime(),
+                        timeRange.getEndTime(), true);
+        var variable = new VariableDefinitionType();
+        variable.setVariableId(VARIABLE_TIMEINRANGE);
+        variable.setExpression(new ObjectFactory().createApply(timeInRange));
+        //
+        // Add it to the policy
+        //
+        newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(variable);
+        //
+        // Create and return the reference to the variable
+        //
+        var reference = new VariableReferenceType();
+        reference.setVariableId(variable.getVariableId());
+        return reference;
+    }
+
+    private Object parseTimestamp(String string) throws ToscaPolicyConversionException {
+        //
+        // First see if it is a full datetime object
+        //
+        try {
+            return OffsetDateTime.parse(string);
+        } catch (Exception e) {
+            LOGGER.warn("timestamp {} could not be parsed. This may not be an error.", string, e);
+        }
+        //
+        // May only be a time object
+        //
+        try {
+            return OffsetTime.parse(string);
+        } catch (Exception e) {
+            throw new ToscaPolicyConversionException("timestamp " + string + " could not be parsed ", e);
         }
-        String timeUnits = null;
-        if (toscaPolicy.getProperties().containsKey(FIELD_TIMEUNITS)) {
-            timeUnits = toscaPolicy.getProperties().get(FIELD_TIMEUNITS).toString();
+    }
+
+    protected void generateFrequencyRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
+            throws ToscaPolicyConversionException {
+        //
+        // Decode the definition from the policy's properties
+        //
+        FrequencyDefinition frequencyDef = ToscaPolicyTranslatorUtils.decodeProperties(toscaPolicy.getProperties(),
+                        FrequencyDefinition.class);
+        //
+        // See if its possible to generate a count
+        //
+        String timeWindow = null;
+        if (frequencyDef.getTimeWindow() != null) {
+            timeWindow = frequencyDef.getTimeWindow().toString();
         }
         //
         // Generate a count
         //
-        final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits);
+        final ApplyType countCheck =
+                        generateCountCheck(frequencyDef.getLimit(), timeWindow, frequencyDef.getTimeUnits());
         //
         // Create our condition
         //
-        final ConditionType condition = new ConditionType();
+        final var condition = new ConditionType();
         condition.setExpression(new ObjectFactory().createApply(countCheck));
 
         //
         // Now we can create our rule
         //
-        RuleType frequencyRule = new RuleType();
+        var frequencyRule = new RuleType();
         frequencyRule.setDescription("Frequency limit permit rule");
         frequencyRule.setRuleId(policyName + ":frequency");
         frequencyRule.setEffect(EffectType.PERMIT);
@@ -367,7 +495,7 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     }
 
     protected ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) {
-        AttributeDesignatorType designator = new AttributeDesignatorType();
+        var designator = new AttributeDesignatorType();
         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue());
         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
@@ -380,7 +508,7 @@ public class GuardTranslator implements ToscaPolicyTranslator {
             + ":tw:" + timeWindow + ":" + timeUnits;
         designator.setIssuer(issuer);
 
-        AttributeValueType valueLimit = new AttributeValueType();
+        var valueLimit = new AttributeValueType();
         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
         //
         // Yes really use toString(), the marshaller will
@@ -389,14 +517,14 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         //
         valueLimit.getContent().add(limit.toString());
 
-        ObjectFactory factory = new ObjectFactory();
+        var factory = new ObjectFactory();
 
-        ApplyType applyOneAndOnly = new ApplyType();
+        var applyOneAndOnly = new ApplyType();
         applyOneAndOnly.setDescription("Unbag the limit");
         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
 
-        ApplyType applyLessThan = new ApplyType();
+        var applyLessThan = new ApplyType();
         applyLessThan.setDescription("return true if current count is less than.");
         applyLessThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN.stringValue());
         applyLessThan.getExpression().add(factory.createApply(applyOneAndOnly));
@@ -408,14 +536,16 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     protected void generateMinMaxRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
             throws ToscaPolicyConversionException {
         //
+        // Decode the definition from the policy's properties
+        //
+        MinMaxDefinition minMaxDef = ToscaPolicyTranslatorUtils.decodeProperties(toscaPolicy.getProperties(),
+                        MinMaxDefinition.class);
+        //
         // Add the target
         //
-        if (! toscaPolicy.getProperties().containsKey(FIELD_TARGET)) {
-            throw new ToscaPolicyConversionException("Missing target field in minmax policy");
-        }
-        MatchType matchTarget = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+        var matchTarget = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                 XACML3.ID_FUNCTION_STRING_EQUAL,
-                toscaPolicy.getProperties().get(FIELD_TARGET).toString(),
+                minMaxDef.getTarget(),
                 XACML3.ID_DATATYPE_STRING,
                 ToscaDictionary.ID_RESOURCE_GUARD_TARGETID,
                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
@@ -423,12 +553,10 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         // For the min, if the # of instances is less than the minimum
         // then allow the scale.
         //
-        Integer min = null;
-        if (toscaPolicy.getProperties().containsKey(FIELD_MIN)) {
-            min = ToscaPolicyTranslatorUtils.parseInteger(toscaPolicy.getProperties().get(FIELD_MIN).toString());
-            MatchType matchMin = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+        if (minMaxDef.getMin() != null) {
+            var matchMin = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                     XACML3.ID_FUNCTION_INTEGER_GREATER_THAN,
-                    min.toString(),
+                    minMaxDef.getMin().toString(),
                     XACML3.ID_DATATYPE_INTEGER,
                     ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT,
                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
@@ -436,12 +564,10 @@ public class GuardTranslator implements ToscaPolicyTranslator {
             newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(
                     generateMinMaxRule(matchTarget, matchMin, policyName + ":minrule", "check minimum"));
         }
-        Integer max = null;
-        if (toscaPolicy.getProperties().containsKey(FIELD_MAX)) {
-            max = ToscaPolicyTranslatorUtils.parseInteger(toscaPolicy.getProperties().get(FIELD_MAX).toString());
-            MatchType matchMax = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+        if (minMaxDef.getMax() != null) {
+            var matchMax = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
                     XACML3.ID_FUNCTION_INTEGER_GREATER_THAN,
-                    max.toString(),
+                    minMaxDef.getMax().toString(),
                     XACML3.ID_DATATYPE_INTEGER,
                     ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT,
                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
@@ -452,20 +578,20 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         //
         // Do we have at least a min or max?
         //
-        if (min == null && max == null) {
+        if (minMaxDef.getMin() == null && minMaxDef.getMax() == null) {
             throw new ToscaPolicyConversionException("Missing min or max field in minmax policy");
         }
     }
 
     protected RuleType generateMinMaxRule(MatchType matchTarget, MatchType matchMinOrMax, String ruleId, String desc) {
-        AllOfType allOf = new AllOfType();
+        var allOf = new AllOfType();
         allOf.getMatch().add(matchTarget);
         allOf.getMatch().add(matchMinOrMax);
-        AnyOfType anyOf = new AnyOfType();
+        var anyOf = new AnyOfType();
         anyOf.getAllOf().add(allOf);
-        TargetType target = new TargetType();
+        var target = new TargetType();
         target.getAnyOf().add(anyOf);
-        RuleType minMaxRule = new RuleType();
+        var minMaxRule = new RuleType();
         minMaxRule.setEffect(EffectType.PERMIT);
         minMaxRule.setDescription(desc);
         minMaxRule.setRuleId(ruleId);
@@ -476,25 +602,29 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     protected void generateBlacklistRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
             throws ToscaPolicyConversionException {
         //
-        // Validate the blacklist exists
+        // Decode the definition from the policy's properties
+        //
+        BlacklistDefinition blacklistDef = ToscaPolicyTranslatorUtils.decodeProperties(toscaPolicy.getProperties(),
+                        BlacklistDefinition.class);
         //
-        if (! toscaPolicy.getProperties().containsKey(FIELD_BLACKLIST)) {
-            throw new ToscaPolicyConversionException("Missing blacklist field");
+        // Iterate the entries and create individual AnyOf so each entry is
+        // treated as an OR.
+        //
+        var target = new TargetType();
+        var anyOf = new AnyOfType();
+        for (Object blacklisted : blacklistDef.blacklist) {
+            var allOf = new AllOfType();
+            this.addMatch(allOf, blacklisted, ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
+            anyOf.getAllOf().add(allOf);
         }
-        final AllOfType allOf = new AllOfType();
-        this.addMatch(allOf, toscaPolicy.getProperties().get(FIELD_BLACKLIST),
-                ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
+        target.getAnyOf().add(anyOf);
         //
         // Create our rule and add the target
         //
-        RuleType blacklistRule = new RuleType();
+        var blacklistRule = new RuleType();
         blacklistRule.setEffect(EffectType.DENY);
         blacklistRule.setDescription("blacklist the entities");
         blacklistRule.setRuleId(policyName + ":blacklist");
-        TargetType target = new TargetType();
-        AnyOfType anyOf = new AnyOfType();
-        anyOf.getAllOf().add(allOf);
-        target.getAnyOf().add(anyOf);
         blacklistRule.setTarget(target);
         //
         // Add the rule to the policy
@@ -502,4 +632,184 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(blacklistRule);
     }
 
+    protected void generateFilterRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
+            throws ToscaPolicyConversionException {
+        //
+        // Decode the definition from the policy's properties
+        //
+        FilterDefinition filterDef = ToscaPolicyTranslatorUtils.decodeProperties(toscaPolicy.getProperties(),
+                        FilterDefinition.class);
+        //
+        // Set the combining algorithm
+        //
+        switch (filterDef.getAlgorithm()) {
+            case "whitelist-overrides":
+                newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_OVERRIDES.stringValue());
+                break;
+            case "blacklist-overrides":
+                newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_OVERRIDES.stringValue());
+                break;
+            default:
+                throw new ToscaPolicyConversionException(
+                                "Unexpected value for algorithm, should be whitelist-overrides or blacklist-overrides");
+        }
+        //
+        // Iterate the filters
+        //
+        var ruleId = 1;
+        for (FilterAttribute filterAttributes : filterDef.filters) {
+            //
+            // Check fields requiring extra validation
+            //
+            String field = validateFilterPropertyField(filterAttributes.getField());
+            Identifier function = validateFilterPropertyFunction(filterAttributes.getFunction());
+            //
+            // Create our filter rule
+            //
+            RuleType filterRule = createFilterRule(policyName + ":rule" + ruleId++, field, filterAttributes.getFilter(),
+                            function, filterAttributes.getBlacklist());
+            //
+            // Add the rule to the policy
+            //
+            newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(filterRule);
+        }
+    }
+
+    private String validateFilterPropertyField(String field)
+            throws ToscaPolicyConversionException {
+        String fieldLowerCase = field.toLowerCase();
+        switch (fieldLowerCase) {
+            case "generic-vnf.vnf-name":
+            case "generic-vnf.vnf-id":
+            case "generic-vnf.vnf-type":
+            case "generic-vnf.nf-naming-code":
+            case "vserver.vserver-id":
+            case "cloud-region.cloud-region-id":
+                return fieldLowerCase;
+            default:
+                throw new ToscaPolicyConversionException("Unexpected value for field in filter");
+        }
+    }
+
+    private Identifier validateFilterPropertyFunction(String function)
+            throws ToscaPolicyConversionException {
+        switch (function.toLowerCase()) {
+            case "string-equal":
+                return XACML3.ID_FUNCTION_STRING_EQUAL;
+            case "string-equal-ignore-case":
+                return XACML3.ID_FUNCTION_STRING_EQUAL_IGNORE_CASE;
+            case "string-regexp-match":
+                return XACML3.ID_FUNCTION_STRING_REGEXP_MATCH;
+            case "string-contains":
+                return XACML3.ID_FUNCTION_STRING_CONTAINS;
+            case "string-greater-than":
+                return XACML3.ID_FUNCTION_STRING_GREATER_THAN;
+            case "string-greater-than-or-equal":
+                return XACML3.ID_FUNCTION_STRING_GREATER_THAN_OR_EQUAL;
+            case "string-less-than":
+                return XACML3.ID_FUNCTION_STRING_LESS_THAN;
+            case "string-less-than-or-equal":
+                return XACML3.ID_FUNCTION_STRING_LESS_THAN_OR_EQUAL;
+            case "string-starts-with":
+                return XACML3.ID_FUNCTION_STRING_STARTS_WITH;
+            case "string-ends-with":
+                return XACML3.ID_FUNCTION_STRING_ENDS_WITH;
+            default:
+                throw new ToscaPolicyConversionException("Unexpected value for function in filter");
+        }
+    }
+
+    private RuleType createFilterRule(String ruleId, String field, String filter, Identifier function,
+            boolean isBlacklisted) {
+        var rule = new RuleType();
+        rule.setRuleId(ruleId);
+
+        //
+        // Create the Match
+        //
+        var matchFilter = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                function,
+                filter,
+                XACML3.ID_DATATYPE_STRING,
+                new IdentifierImpl(GuardPolicyRequest.PREFIX_RESOURCE_ATTRIBUTE_ID + field),
+                XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE
+                );
+        var allOf = new AllOfType();
+        allOf.getMatch().add(matchFilter);
+        var anyOf = new AnyOfType();
+        anyOf.getAllOf().add(allOf);
+        var target = new TargetType();
+        target.getAnyOf().add(anyOf);
+
+        rule.setTarget(target);
+
+        if (isBlacklisted) {
+            rule.setEffect(EffectType.DENY);
+        } else {
+            rule.setEffect(EffectType.PERMIT);
+        }
+        return rule;
+    }
+
+    @Getter
+    public static class TimeRangeDefinition {
+        private @Valid TimeRange timeRange;
+    }
+
+    @Getter
+    public static class TargetTypeDefinition {
+        private String actor;
+        private String operation;
+        private String target;
+        private String id;
+    }
+
+    @Getter
+    @NotNull
+    @NotBlank
+    public static class TimeRange {
+        @SerializedName("start_time")
+        private String startTime;
+
+        @SerializedName("end_time")
+        private String endTime;
+    }
+
+    @Getter
+    public static class FrequencyDefinition {
+        @NotNull
+        private Integer limit;
+        private Integer timeWindow;
+        private String timeUnits;
+    }
+
+    @Getter
+    public static class MinMaxDefinition {
+        @NotNull
+        private String target;
+        private Integer min;
+        private Integer max;
+    }
+
+    @Getter
+    @NotNull
+    public static class BlacklistDefinition {
+        private List<@NotNull Object> blacklist;
+    }
+
+    @Getter
+    @NotNull
+    public static class FilterDefinition {
+        private String algorithm;
+        private List<@NotNull @Valid FilterAttribute> filters;
+    }
+
+    @Getter
+    @NotNull
+    public static class FilterAttribute {
+        private String field;
+        private String filter;
+        private String function;
+        private Boolean blacklist;
+    }
 }