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