b3ee36bcde3584476023d0033a8324e62a28ec71
[policy/xacml-pdp.git] / applications / guard / src / main / java / org / onap / policy / xacml / pdp / application / guard / GuardTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.xacml.pdp.application.guard;
24
25 import com.att.research.xacml.api.DataTypeException;
26 import com.att.research.xacml.api.Decision;
27 import com.att.research.xacml.api.Identifier;
28 import com.att.research.xacml.api.Request;
29 import com.att.research.xacml.api.Response;
30 import com.att.research.xacml.api.Result;
31 import com.att.research.xacml.api.XACML3;
32 import com.att.research.xacml.std.IdentifierImpl;
33 import com.att.research.xacml.std.annotations.RequestParser;
34 import java.util.Collection;
35 import java.util.Map;
36 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
48 import org.onap.policy.models.decisions.concepts.DecisionRequest;
49 import org.onap.policy.models.decisions.concepts.DecisionResponse;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
51 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
52 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
53 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
54 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
55 import org.onap.policy.pdp.xacml.application.common.operationshistory.CountRecentOperationsPip;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public class GuardTranslator implements ToscaPolicyTranslator {
60     private static final Logger LOGGER = LoggerFactory.getLogger(GuardTranslator.class);
61
62     //
63     // common guard property fields
64     //
65     public static final String FIELD_ACTOR = "actor";
66     public static final String FIELD_OPERATION = "operation";
67     public static final String FIELD_CONTROLLOOP = "id";
68     public static final String FIELD_TIMERANGE = "timeRange";
69
70     //
71     // frequency property fields
72     //
73     public static final String FIELD_TIMEWINDOW = "timeWindow";
74     public static final String FIELD_TIMEUNITS = "timeUnits";
75     public static final String FIELD_LIMIT = "limit";
76
77     //
78     // minmax property fields
79     //
80     public static final String FIELD_TARGET = "target";
81     public static final String FIELD_MIN = "min";
82     public static final String FIELD_MAX = "max";
83
84     //
85     // blacklist property fields
86     //
87     public static final String FIELD_BLACKLIST = "blacklist";
88
89     //
90     // filter property fields
91     //
92     public static final String FIELD_FILTER_WHITELIST = "whitelist";
93     public static final String FIELD_FILTER_ALGORITHM = "algorithm";
94     public static final String FIELD_FILTER_FILTERS = "filters";
95     public static final String FIELD_FILTER_FIELD = "field";
96     public static final String FIELD_FILTER_FUNCTION = "function";
97     public static final String FIELD_FILTER_FILTER = "filter";
98     public static final String FIELD_FILTER_BLACKLIST = "blacklist";
99
100     public static final String POLICYTYPE_FREQUENCY = "onap.policies.controlloop.guard.common.FrequencyLimiter";
101     public static final String POLICYTYPE_MINMAX = "onap.policies.controlloop.guard.common.MinMax";
102     public static final String POLICYTYPE_BLACKLIST = "onap.policies.controlloop.guard.common.Blacklist";
103     public static final String POLICYTYPE_FILTER = "onap.policies.controlloop.guard.common.Filter";
104
105     public GuardTranslator() {
106         super();
107     }
108
109     /**
110      * Convert the policy.
111      */
112     @Override
113     public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
114         //
115         // Policy name should be at the root
116         //
117         String policyName = toscaPolicy.getMetadata().get("policy-id");
118         //
119         // Set it as the policy ID
120         //
121         PolicyType newPolicyType = new PolicyType();
122         newPolicyType.setPolicyId(policyName);
123         //
124         // Optional description
125         //
126         newPolicyType.setDescription(toscaPolicy.getDescription());
127         //
128         // There should be a metadata section
129         //
130         this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
131         //
132         // Generate the TargetType - add true if not blacklist
133         //
134         newPolicyType.setTarget(this.generateTargetType(toscaPolicy.getProperties(),
135                 ! POLICYTYPE_BLACKLIST.equals(toscaPolicy.getType())));
136         //
137         // Add specific's per guard policy type
138         //
139         if (POLICYTYPE_FREQUENCY.equals(toscaPolicy.getType())) {
140             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
141             generateFrequencyRules(toscaPolicy, policyName, newPolicyType);
142         } else if (POLICYTYPE_MINMAX.equals(toscaPolicy.getType())) {
143             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
144             generateMinMaxRules(toscaPolicy, policyName, newPolicyType);
145         } else if (POLICYTYPE_BLACKLIST.equals(toscaPolicy.getType())) {
146             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
147             generateBlacklistRules(toscaPolicy, policyName, newPolicyType);
148         } else if (POLICYTYPE_FILTER.equals(toscaPolicy.getType())) {
149             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
150             generateFilterRules(toscaPolicy, policyName, newPolicyType);
151         } else {
152             throw new ToscaPolicyConversionException("Unknown guard policy type " + toscaPolicy.getType());
153         }
154         return newPolicyType;
155     }
156
157     /**
158      * Convert Request.
159      */
160     @Override
161     public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
162         LOGGER.info("Converting Request {}", request);
163         try {
164             return RequestParser.parseRequest(GuardPolicyRequest.createInstance(request));
165         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
166             throw new ToscaPolicyConversionException("Failed to convert DecisionRequest", e);
167         }
168     }
169
170     /**
171      * Convert response.
172      */
173     @Override
174     public DecisionResponse convertResponse(Response xacmlResponse) {
175         LOGGER.info("Converting Response {}", xacmlResponse);
176         DecisionResponse decisionResponse = new DecisionResponse();
177         //
178         // Iterate through all the results
179         //
180         for (Result xacmlResult : xacmlResponse.getResults()) {
181             //
182             // Check the result
183             //
184             if (xacmlResult.getDecision() == Decision.PERMIT) {
185                 //
186                 // Just simply return a Permit response
187                 //
188                 decisionResponse.setStatus(Decision.PERMIT.toString());
189             } else if (xacmlResult.getDecision() == Decision.DENY) {
190                 //
191                 // Just simply return a Deny response
192                 //
193                 decisionResponse.setStatus(Decision.DENY.toString());
194             } else {
195                 //
196                 // There is no guard policy, so we return a permit
197                 //
198                 decisionResponse.setStatus(Decision.PERMIT.toString());
199             }
200         }
201
202         return decisionResponse;
203     }
204
205     /**
206      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
207      *
208      * @param policy Policy Object to store the metadata
209      * @param map The Metadata TOSCA Map
210      * @return Same Policy Object
211      */
212     protected PolicyType fillMetadataSection(PolicyType policy, Map<String, String> map) {
213         //
214         // NOTE: The models code ensures the metadata section ALWAYS exists
215         //
216         //
217         // Add in the Policy Version
218         //
219         policy.setVersion(map.get("policy-version"));
220         return policy;
221     }
222
223     /**
224      * Generate the targettype for the policy. Optional to add MatchType for the target. eg. the
225      * blacklist policy type uses the target in a different manner.
226      *
227      * @param properties TOSCA properties object
228      * @param addTargets true to go ahead and add target to the match list.
229      * @return TargetType object
230      * @throws ToscaPolicyConversionException if there is a missing property
231      */
232     protected TargetType generateTargetType(Map<String, Object> properties, boolean addTargets)
233             throws ToscaPolicyConversionException {
234         //
235         // Go through potential properties
236         //
237         AllOfType allOf = new AllOfType();
238         if (properties.containsKey(FIELD_ACTOR)) {
239             addMatch(allOf, properties.get(FIELD_ACTOR), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
240         }
241         if (properties.containsKey(FIELD_OPERATION)) {
242             addMatch(allOf, properties.get(FIELD_OPERATION), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
243         }
244         if (addTargets && properties.containsKey(FIELD_TARGET)) {
245             addMatch(allOf, properties.get(FIELD_TARGET), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
246         }
247         if (properties.containsKey(FIELD_CONTROLLOOP)) {
248             addMatch(allOf, properties.get(FIELD_CONTROLLOOP), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME);
249         }
250         if (properties.containsKey(FIELD_TIMERANGE)) {
251             addTimeRangeMatch(allOf, properties.get(FIELD_TIMERANGE));
252         }
253         //
254         // Create target
255         //
256         TargetType target = new TargetType();
257         AnyOfType anyOf = new AnyOfType();
258         anyOf.getAllOf().add(allOf);
259         target.getAnyOf().add(anyOf);
260         return target;
261     }
262
263     @SuppressWarnings("unchecked")
264     protected AllOfType addMatch(AllOfType allOf, Object value, Identifier attributeId) {
265         if (value instanceof String) {
266             if (".*".equals(value.toString())) {
267                 //
268                 // There's no point to even have a match
269                 //
270                 return allOf;
271             } else {
272                 //
273                 // Exact match
274                 //
275                 MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
276                     XACML3.ID_FUNCTION_STRING_EQUAL,
277                     value,
278                     XACML3.ID_DATATYPE_STRING,
279                     attributeId,
280                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
281
282                 allOf.getMatch().add(match);
283             }
284             return allOf;
285         }
286         if (value instanceof Collection) {
287             ((Collection<String>) value).forEach(val -> {
288                 MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
289                         XACML3.ID_FUNCTION_STRING_EQUAL,
290                         val,
291                         XACML3.ID_DATATYPE_STRING,
292                         attributeId,
293                         XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
294
295                 allOf.getMatch().add(match);
296             });
297         }
298         return allOf;
299     }
300
301     @SuppressWarnings("rawtypes")
302     protected void addTimeRangeMatch(AllOfType allOf, Object timeRange)
303             throws ToscaPolicyConversionException {
304         if (! (timeRange instanceof Map)) {
305             throw new ToscaPolicyConversionException("timeRange is not a map object " + timeRange.getClass());
306         }
307
308         MatchType matchStart = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
309                 XACML3.ID_FUNCTION_TIME_GREATER_THAN_OR_EQUAL,
310                 ((Map) timeRange).get("start_time").toString(),
311                 XACML3.ID_DATATYPE_TIME,
312                 XACML3.ID_ENVIRONMENT_CURRENT_TIME,
313                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
314
315         allOf.getMatch().add(matchStart);
316
317         MatchType matchEnd = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
318                 XACML3.ID_FUNCTION_TIME_LESS_THAN_OR_EQUAL,
319                 ((Map) timeRange).get("end_time").toString(),
320                 XACML3.ID_DATATYPE_TIME,
321                 XACML3.ID_ENVIRONMENT_CURRENT_TIME,
322                 XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT);
323
324         allOf.getMatch().add(matchEnd);
325     }
326
327     protected void generateFrequencyRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
328             throws ToscaPolicyConversionException {
329         //
330         // We must have the limit
331         //
332         if (! toscaPolicy.getProperties().containsKey(FIELD_LIMIT)) {
333             throw new ToscaPolicyConversionException("Missing property limit");
334         }
335         //
336         // See if its possible to generate a count
337         //
338         Integer limit = ToscaPolicyTranslatorUtils.parseInteger(
339                 toscaPolicy.getProperties().get(FIELD_LIMIT).toString());
340         if (limit == null) {
341             throw new ToscaPolicyConversionException("Missing limit value");
342         }
343         String timeWindow = null;
344         if (toscaPolicy.getProperties().containsKey(FIELD_TIMEWINDOW)) {
345             Integer intTimeWindow = ToscaPolicyTranslatorUtils.parseInteger(
346                     toscaPolicy.getProperties().get(FIELD_TIMEWINDOW).toString());
347             if (intTimeWindow == null) {
348                 throw new ToscaPolicyConversionException("timeWindow is not an integer");
349             }
350             timeWindow = intTimeWindow.toString();
351         }
352         String timeUnits = null;
353         if (toscaPolicy.getProperties().containsKey(FIELD_TIMEUNITS)) {
354             timeUnits = toscaPolicy.getProperties().get(FIELD_TIMEUNITS).toString();
355         }
356         //
357         // Generate a count
358         //
359         final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits);
360         //
361         // Create our condition
362         //
363         final ConditionType condition = new ConditionType();
364         condition.setExpression(new ObjectFactory().createApply(countCheck));
365
366         //
367         // Now we can create our rule
368         //
369         RuleType frequencyRule = new RuleType();
370         frequencyRule.setDescription("Frequency limit permit rule");
371         frequencyRule.setRuleId(policyName + ":frequency");
372         frequencyRule.setEffect(EffectType.PERMIT);
373         frequencyRule.setTarget(new TargetType());
374         //
375         // Add the condition
376         //
377         frequencyRule.setCondition(condition);
378         //
379         // Add the rule to the policy
380         //
381         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(frequencyRule);
382     }
383
384     protected ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) {
385         AttributeDesignatorType designator = new AttributeDesignatorType();
386         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue());
387         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
388         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
389         //
390         // Setup issuer - used by the operations PIP to determine
391         // how to do the database query.
392         //
393         String issuer = ToscaDictionary.GUARD_ISSUER_PREFIX
394             + CountRecentOperationsPip.ISSUER_NAME
395             + ":tw:" + timeWindow + ":" + timeUnits;
396         designator.setIssuer(issuer);
397
398         AttributeValueType valueLimit = new AttributeValueType();
399         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
400         //
401         // Yes really use toString(), the marshaller will
402         // throw an exception if this is an integer object
403         // and not a string.
404         //
405         valueLimit.getContent().add(limit.toString());
406
407         ObjectFactory factory = new ObjectFactory();
408
409         ApplyType applyOneAndOnly = new ApplyType();
410         applyOneAndOnly.setDescription("Unbag the limit");
411         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
412         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
413
414         ApplyType applyLessThan = new ApplyType();
415         applyLessThan.setDescription("return true if current count is less than.");
416         applyLessThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN.stringValue());
417         applyLessThan.getExpression().add(factory.createApply(applyOneAndOnly));
418         applyLessThan.getExpression().add(factory.createAttributeValue(valueLimit));
419
420         return applyLessThan;
421     }
422
423     protected void generateMinMaxRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
424             throws ToscaPolicyConversionException {
425         //
426         // Add the target
427         //
428         if (! toscaPolicy.getProperties().containsKey(FIELD_TARGET)) {
429             throw new ToscaPolicyConversionException("Missing target field in minmax policy");
430         }
431         MatchType matchTarget = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
432                 XACML3.ID_FUNCTION_STRING_EQUAL,
433                 toscaPolicy.getProperties().get(FIELD_TARGET).toString(),
434                 XACML3.ID_DATATYPE_STRING,
435                 ToscaDictionary.ID_RESOURCE_GUARD_TARGETID,
436                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
437         //
438         // For the min, if the # of instances is less than the minimum
439         // then allow the scale.
440         //
441         Integer min = null;
442         if (toscaPolicy.getProperties().containsKey(FIELD_MIN)) {
443             min = ToscaPolicyTranslatorUtils.parseInteger(toscaPolicy.getProperties().get(FIELD_MIN).toString());
444             MatchType matchMin = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
445                     XACML3.ID_FUNCTION_INTEGER_GREATER_THAN,
446                     min.toString(),
447                     XACML3.ID_DATATYPE_INTEGER,
448                     ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT,
449                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
450
451             newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(
452                     generateMinMaxRule(matchTarget, matchMin, policyName + ":minrule", "check minimum"));
453         }
454         Integer max = null;
455         if (toscaPolicy.getProperties().containsKey(FIELD_MAX)) {
456             max = ToscaPolicyTranslatorUtils.parseInteger(toscaPolicy.getProperties().get(FIELD_MAX).toString());
457             MatchType matchMax = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
458                     XACML3.ID_FUNCTION_INTEGER_GREATER_THAN,
459                     max.toString(),
460                     XACML3.ID_DATATYPE_INTEGER,
461                     ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT,
462                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
463
464             newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(
465                     generateMinMaxRule(matchTarget, matchMax, policyName + ":maxrule", "check maximum"));
466         }
467         //
468         // Do we have at least a min or max?
469         //
470         if (min == null && max == null) {
471             throw new ToscaPolicyConversionException("Missing min or max field in minmax policy");
472         }
473     }
474
475     protected RuleType generateMinMaxRule(MatchType matchTarget, MatchType matchMinOrMax, String ruleId, String desc) {
476         AllOfType allOf = new AllOfType();
477         allOf.getMatch().add(matchTarget);
478         allOf.getMatch().add(matchMinOrMax);
479         AnyOfType anyOf = new AnyOfType();
480         anyOf.getAllOf().add(allOf);
481         TargetType target = new TargetType();
482         target.getAnyOf().add(anyOf);
483         RuleType minMaxRule = new RuleType();
484         minMaxRule.setEffect(EffectType.PERMIT);
485         minMaxRule.setDescription(desc);
486         minMaxRule.setRuleId(ruleId);
487         minMaxRule.setTarget(target);
488         return minMaxRule;
489     }
490
491     protected void generateBlacklistRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
492             throws ToscaPolicyConversionException {
493         //
494         // Validate the blacklist exists
495         //
496         if (! toscaPolicy.getProperties().containsKey(FIELD_BLACKLIST)) {
497             throw new ToscaPolicyConversionException("Missing blacklist field");
498         }
499         //
500         // Get the blacklist, which should be an array or collection.
501         //
502         Object arrayBlacklisted = toscaPolicy.getProperties().get(FIELD_BLACKLIST);
503         if (!(arrayBlacklisted instanceof Collection)) {
504             throw new ToscaPolicyConversionException("Blacklist is not a collection");
505         }
506         //
507         // Iterate the entries and create individual AnyOf so each entry is
508         // treated as an OR.
509         //
510         TargetType target = new TargetType();
511         AnyOfType anyOf = new AnyOfType();
512         for (Object blacklisted : ((Collection<?>) arrayBlacklisted)) {
513             AllOfType allOf = new AllOfType();
514             this.addMatch(allOf, blacklisted, ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
515             anyOf.getAllOf().add(allOf);
516         }
517         target.getAnyOf().add(anyOf);
518         //
519         // Create our rule and add the target
520         //
521         RuleType blacklistRule = new RuleType();
522         blacklistRule.setEffect(EffectType.DENY);
523         blacklistRule.setDescription("blacklist the entities");
524         blacklistRule.setRuleId(policyName + ":blacklist");
525         blacklistRule.setTarget(target);
526         //
527         // Add the rule to the policy
528         //
529         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(blacklistRule);
530     }
531
532     @SuppressWarnings("unchecked")
533     protected void generateFilterRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
534             throws ToscaPolicyConversionException {
535         //
536         // Validate the algorithm
537         //
538         if (! toscaPolicy.getProperties().containsKey(FIELD_FILTER_ALGORITHM)) {
539             throw new ToscaPolicyConversionException("Missing algorithm");
540         }
541         Object algorithm = toscaPolicy.getProperties().get(FIELD_FILTER_ALGORITHM);
542         if ("whitelist-overrides".equals(algorithm.toString())) {
543             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_OVERRIDES.stringValue());
544         } else if ("blacklist-overrides".equals(algorithm.toString())) {
545             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_OVERRIDES.stringValue());
546         } else {
547             throw new ToscaPolicyConversionException(
548                     "Unexpected value for algorithm, should be whitelist-overrides or blacklist-overrides");
549         }
550         //
551         // Validate the filters exist and have the right properties
552         //
553         if (! toscaPolicy.getProperties().containsKey(FIELD_FILTER_FILTERS)) {
554             throw new ToscaPolicyConversionException("Missing filters");
555         }
556         //
557         // Get the filters, which should be an array or collection.
558         //
559         Object arrayFilters = toscaPolicy.getProperties().get(FIELD_FILTER_FILTERS);
560         if (!(arrayFilters instanceof Collection)) {
561             throw new ToscaPolicyConversionException("Filters is not a collection");
562         }
563         //
564         // Iterate the filters
565         //
566         int ruleId = 1;
567         for (Object filterAttributes : ((Collection<?>) arrayFilters)) {
568             if (!(filterAttributes instanceof Map)) {
569                 throw new ToscaPolicyConversionException("Filter should be a map");
570             }
571             //
572             // All fields must be there
573             //
574             String field = validateFilterPropertyField((Map<String, Object>) filterAttributes);
575             String filter = validateFilterPropertyFilter((Map<String, Object>) filterAttributes);
576             Identifier function = validateFilterPropertyFunction((Map<String, Object>) filterAttributes);
577             boolean isBlacklisted = validateFilterPropertyBlacklist((Map<String, Object>) filterAttributes);
578             //
579             // Create our filter rule
580             //
581             RuleType filterRule = createFilterRule(policyName + ":rule" + ruleId++, field, filter,
582                     function, isBlacklisted);
583             //
584             // Add the rule to the policy
585             //
586             newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(filterRule);
587         }
588     }
589
590     private String validateFilterPropertyField(Map<String, Object> filterAttributes)
591             throws ToscaPolicyConversionException {
592         Object field = filterAttributes.get(FIELD_FILTER_FIELD);
593         if (field != null) {
594             switch (field.toString().toLowerCase()) {
595                 case "generic-vnf.vnf-name":
596                 case "generic-vnf.vnf-id":
597                 case "generic-vnf.vnf-type":
598                 case "generic-vnf.nf-naming-code":
599                 case "vserver.vserver-id":
600                 case "cloud-region.cloud-region-id":
601                     return field.toString();
602                 default:
603                     throw new ToscaPolicyConversionException("Unexpected value for field in filter");
604             }
605         }
606         throw new ToscaPolicyConversionException("Missing \'field\' from filter");
607     }
608
609     private String validateFilterPropertyFilter(Map<String, Object> filterAttributes)
610             throws ToscaPolicyConversionException {
611         Object filter = filterAttributes.get(FIELD_FILTER_FILTER);
612         if (filter != null) {
613             return filter.toString();
614         }
615         throw new ToscaPolicyConversionException("Missing \'filter\' from filter");
616     }
617
618     private Identifier validateFilterPropertyFunction(Map<String, Object> filterAttributes)
619             throws ToscaPolicyConversionException {
620         Object function = filterAttributes.get(FIELD_FILTER_FUNCTION);
621         if (function != null) {
622             switch (function.toString().toLowerCase()) {
623                 case "string-equal":
624                     return XACML3.ID_FUNCTION_STRING_EQUAL;
625                 case "string-equal-ignore-case":
626                     return XACML3.ID_FUNCTION_STRING_EQUAL_IGNORE_CASE;
627                 case "string-regexp-match":
628                     return XACML3.ID_FUNCTION_STRING_REGEXP_MATCH;
629                 case "string-contains":
630                     return XACML3.ID_FUNCTION_STRING_CONTAINS;
631                 case "string-greater-than":
632                     return XACML3.ID_FUNCTION_STRING_GREATER_THAN;
633                 case "string-greater-than-or-equal":
634                     return XACML3.ID_FUNCTION_STRING_GREATER_THAN_OR_EQUAL;
635                 case "string-less-than":
636                     return XACML3.ID_FUNCTION_STRING_LESS_THAN;
637                 case "string-less-than-or-equal":
638                     return XACML3.ID_FUNCTION_STRING_LESS_THAN_OR_EQUAL;
639                 case "string-starts-with":
640                     return XACML3.ID_FUNCTION_STRING_STARTS_WITH;
641                 case "string-ends-with":
642                     return XACML3.ID_FUNCTION_STRING_ENDS_WITH;
643                 default:
644                     throw new ToscaPolicyConversionException("Unexpected value for function in filter");
645             }
646         }
647         throw new ToscaPolicyConversionException("Missing \'function\' from filter");
648     }
649
650     private boolean validateFilterPropertyBlacklist(Map<String, Object> filterAttributes)
651             throws ToscaPolicyConversionException {
652         Object filter = filterAttributes.get(FIELD_FILTER_BLACKLIST);
653         if (filter != null) {
654             if ("true".equalsIgnoreCase(filter.toString())) {
655                 return true;
656             }
657             if ("false".equalsIgnoreCase(filter.toString())) {
658                 return false;
659             }
660             throw new ToscaPolicyConversionException("Unexpected value for blacklist in filter");
661         }
662         throw new ToscaPolicyConversionException("Missing \'blacklist\' from filter");
663     }
664
665     private RuleType createFilterRule(String ruleId, String field, String filter, Identifier function,
666             boolean isBlacklisted) {
667         RuleType rule = new RuleType();
668         rule.setRuleId(ruleId);
669
670         //
671         // Create the Match
672         //
673         MatchType matchFilter = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
674                 function,
675                 filter,
676                 XACML3.ID_DATATYPE_STRING,
677                 new IdentifierImpl(GuardPolicyRequest.PREFIX_RESOURCE_ATTRIBUTE_ID + field),
678                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE
679                 );
680         AllOfType allOf = new AllOfType();
681         allOf.getMatch().add(matchFilter);
682         AnyOfType anyOf = new AnyOfType();
683         anyOf.getAllOf().add(allOf);
684         TargetType target = new TargetType();
685         target.getAnyOf().add(anyOf);
686
687         rule.setTarget(target);
688
689         if (isBlacklisted) {
690             rule.setEffect(EffectType.DENY);
691         } else {
692             rule.setEffect(EffectType.PERMIT);
693         }
694         return rule;
695     }
696
697 }