Added xacml.properties to packages for native app
[policy/xacml-pdp.git] / applications / guard / src / main / java / org / onap / policy / xacml / pdp / application / guard / LegacyGuardTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019 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.annotations.RequestParser;
33
34 import java.util.Collection;
35 import java.util.Map;
36
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
52
53 import org.onap.policy.models.decisions.concepts.DecisionRequest;
54 import org.onap.policy.models.decisions.concepts.DecisionResponse;
55 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
56 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
57 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
58 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
59 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
60 import org.onap.policy.pdp.xacml.application.common.operationshistory.CountRecentOperationsPip;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class LegacyGuardTranslator implements ToscaPolicyTranslator {
65
66     private static final Logger LOGGER = LoggerFactory.getLogger(LegacyGuardTranslator.class);
67
68     private static final String FIELD_GUARD_ACTIVE_START = "guardActiveStart";
69     private static final String FIELD_GUARD_ACTIVE_END = "guardActiveEnd";
70     private static final String FIELD_TARGET = "targets";
71     private static final String DESC_DEFAULT = "Default is to PERMIT if the policy matches.";
72     private static final String ID_RULE = ":rule";
73
74     public LegacyGuardTranslator() {
75         super();
76     }
77
78     @Override
79     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
80         //
81         // Policy name should be at the root
82         //
83         String policyName = toscaPolicy.getMetadata().get("policy-id");
84         //
85         // Set it as the policy ID
86         //
87         PolicyType newPolicyType = new PolicyType();
88         newPolicyType.setPolicyId(policyName);
89         //
90         // Optional description
91         //
92         newPolicyType.setDescription(toscaPolicy.getDescription());
93         //
94         // There should be a metadata section
95         //
96         this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
97         //
98         // Set the combining rule
99         //
100         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
101         //
102         // Generate the TargetType - add true if not blacklist
103         //
104         newPolicyType.setTarget(this.generateTargetType(toscaPolicy.getProperties(),
105                 ! "onap.policies.controlloop.guard.Blacklist".equals(toscaPolicy.getType())));
106         //
107         // Now create the Permit Rule
108         //
109         RuleType rule = generatePermitRule(policyName, toscaPolicy.getType(), toscaPolicy.getProperties());
110         //
111         // Check if we were able to create the rule
112         //
113         if (rule == null) {
114             LOGGER.error("Failed to create rule");
115             return null;
116         }
117         //
118         // Add the rule to the policy
119         //
120         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
121         //
122         // Return our new policy
123         //
124         return newPolicyType;
125     }
126
127     @Override
128     public Request convertRequest(DecisionRequest request) {
129         LOGGER.info("Converting Request {}", request);
130         try {
131             return RequestParser.parseRequest(LegacyGuardPolicyRequest.createInstance(request));
132         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
133             LOGGER.error("Failed to convert DecisionRequest: {}", e);
134         }
135         //
136         // TODO throw exception
137         //
138         return null;
139     }
140
141     @Override
142     public DecisionResponse convertResponse(Response xacmlResponse) {
143         LOGGER.info("Converting Response {}", xacmlResponse);
144         DecisionResponse decisionResponse = new DecisionResponse();
145         //
146         // Iterate through all the results
147         //
148         for (Result xacmlResult : xacmlResponse.getResults()) {
149             //
150             // Check the result
151             //
152             if (xacmlResult.getDecision() == Decision.PERMIT) {
153                 //
154                 // Just simply return a Permit response
155                 //
156                 decisionResponse.setStatus(Decision.PERMIT.toString());
157             }
158             if (xacmlResult.getDecision() == Decision.DENY) {
159                 //
160                 // Just simply return a Deny response
161                 //
162                 decisionResponse.setStatus(Decision.DENY.toString());
163             }
164             if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
165                 //
166                 // There is no guard policy, so we return a permit
167                 //
168                 decisionResponse.setStatus(Decision.PERMIT.toString());
169             }
170         }
171
172         return decisionResponse;
173     }
174
175     /**
176      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
177      *
178      * @param policy Policy Object to store the metadata
179      * @param map The Metadata TOSCA Map
180      * @return Same Policy Object
181      * @throws ToscaPolicyConversionException If there is something missing from the metadata
182      */
183     protected PolicyType fillMetadataSection(PolicyType policy,
184             Map<String, String> map) throws ToscaPolicyConversionException {
185         if (! map.containsKey("policy-id")) {
186             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
187         } else {
188             //
189             // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
190             //
191         }
192         if (! map.containsKey("policy-version")) {
193             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
194         } else {
195             //
196             // Add in the Policy Version
197             //
198             policy.setVersion(map.get("policy-version"));
199         }
200         return policy;
201     }
202
203     protected TargetType generateTargetType(Map<String, Object> properties, boolean addTargets) {
204         //
205         // Go through potential properties
206         //
207         AllOfType allOf = new AllOfType();
208         if (properties.containsKey("actor")) {
209             addMatch(allOf, properties.get("actor"), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
210         }
211         if (properties.containsKey("recipe")) {
212             addMatch(allOf, properties.get("recipe"), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
213         }
214         if (addTargets && properties.containsKey(FIELD_TARGET)) {
215             addMatch(allOf, properties.get(FIELD_TARGET), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
216         }
217         if (properties.containsKey("clname")) {
218             addMatch(allOf, properties.get("clname"), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME);
219         }
220         //
221         // Create target
222         //
223         TargetType target = new TargetType();
224         AnyOfType anyOf = new AnyOfType();
225         anyOf.getAllOf().add(allOf);
226         target.getAnyOf().add(anyOf);
227         return target;
228     }
229
230     private static AllOfType addMatch(AllOfType allOf, Object value, Identifier attributeId) {
231         if (value instanceof String) {
232             if (".*".equals(value.toString())) {
233                 //
234                 // There's no point to even have a match
235                 //
236                 return allOf;
237             } else {
238                 //
239                 // Exact match
240                 //
241                 MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
242                     XACML3.ID_FUNCTION_STRING_EQUAL,
243                     value,
244                     XACML3.ID_DATATYPE_STRING,
245                     attributeId,
246                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
247
248                 allOf.getMatch().add(match);
249             }
250             return allOf;
251         }
252         if (value instanceof Collection) {
253             //
254             // TODO support a collection of that attribute
255             //
256         }
257         return allOf;
258     }
259
260     private static RuleType generatePermitRule(String policyName, String policyType, Map<String, Object> properties)
261             throws ToscaPolicyConversionException {
262         //
263         // Now determine which policy type we are generating
264         //
265         if ("onap.policies.controlloop.guard.FrequencyLimiter".equals(policyType)) {
266             return generateFrequencyPermit(policyName, properties);
267         } else if ("onap.policies.controlloop.guard.MinMax".equals(policyType)) {
268             return generateMinMaxPermit(policyName, properties);
269         } else if ("onap.policies.controlloop.guard.Blacklist".equals(policyType)) {
270             return generateBlacklistPermit(policyName, properties);
271         }
272         LOGGER.error("Missing policy type in the policy");
273         return null;
274     }
275
276     private static RuleType generateFrequencyPermit(String policyName, Map<String, Object> properties)
277             throws ToscaPolicyConversionException {
278         //
279         // See if its possible to generate a count
280         //
281         Integer limit = parseInteger(properties.get("limit").toString());
282         if (limit == null) {
283             LOGGER.error("Must have a limit value for frequency guard policy to be created");
284             return null;
285         }
286         //
287         // Get the properties that are common among guards
288         //
289         String timeWindow = null;
290         if (properties.containsKey("timeWindow")) {
291             Integer intTimeWindow = parseInteger(properties.get("timeWindow").toString());
292             if (intTimeWindow == null) {
293                 throw new ToscaPolicyConversionException("timeWindow is not an integer");
294             }
295             timeWindow = intTimeWindow.toString();
296         }
297         String timeUnits = null;
298         if (properties.containsKey("timeUnits")) {
299             timeUnits = properties.get("timeUnits").toString();
300         }
301         String guardActiveStart = null;
302         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
303             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
304         }
305         String guardActiveEnd = null;
306         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
307             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
308         }
309         //
310         // Generate the time in range
311         //
312         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
313         //
314         // Generate a count
315         //
316         final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits);
317         //
318         // Now combine into an And
319         //
320         ApplyType applyAnd = new ApplyType();
321         applyAnd.setDescription("return true if time range and count checks are true.");
322         applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
323         applyAnd.getExpression().add(new ObjectFactory().createApply(timeRange));
324         applyAnd.getExpression().add(new ObjectFactory().createApply(countCheck));
325
326         //
327         // Create our condition
328         //
329         final ConditionType condition = new ConditionType();
330         condition.setExpression(new ObjectFactory().createApply(applyAnd));
331
332         //
333         // Now we can create our rule
334         //
335         RuleType permit = new RuleType();
336         permit.setDescription(DESC_DEFAULT);
337         permit.setRuleId(policyName + ID_RULE);
338         permit.setEffect(EffectType.PERMIT);
339         permit.setTarget(new TargetType());
340         //
341         // Add the condition
342         //
343         permit.setCondition(condition);
344         //
345         // Done
346         //
347         return permit;
348     }
349
350     private static RuleType generateMinMaxPermit(String policyName, Map<String, Object> properties) {
351         //
352         // Get the properties that are common among guards
353         //
354         String guardActiveStart = null;
355         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
356             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
357         }
358         String guardActiveEnd = null;
359         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
360             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
361         }
362         //
363         // Generate the time in range
364         //
365         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
366         //
367         // See if its possible to generate a count
368         //
369         Integer min = null;
370         if (properties.containsKey("min")) {
371             min = parseInteger(properties.get("min").toString());
372         }
373         Integer max = null;
374         if (properties.containsKey("max")) {
375             max = parseInteger(properties.get("max").toString());
376         }
377         final ApplyType minApply = generateMinCheck(min);
378         final ApplyType maxApply = generateMaxCheck(max);
379         //
380         // Make sure we have at least something to check here,
381         // otherwise there really is no point to this policy.
382         //
383         if (timeRange == null && minApply == null && maxApply == null) {
384             return null;
385         }
386         //
387         // Create our rule
388         //
389         RuleType permit = new RuleType();
390         permit.setDescription(DESC_DEFAULT);
391         permit.setRuleId(policyName + ID_RULE);
392         permit.setEffect(EffectType.PERMIT);
393         permit.setTarget(new TargetType());
394         //
395         // Create the condition
396         //
397         permit.setCondition(createCondition(timeRange, minApply, maxApply));
398         //
399         // Done
400         //
401         return permit;
402     }
403
404     private static ConditionType createCondition(ApplyType timeRange, ApplyType minApply, ApplyType maxApply) {
405         final ConditionType condition = new ConditionType();
406         //
407         // Check if we have all the fields (this can be a little
408         // ugly) but the ultimate goal is to simplify the policy
409         // condition to only check for necessary attributes.
410         //
411         ObjectFactory factory = new ObjectFactory();
412         if (timeRange != null && minApply != null && maxApply != null) {
413             //
414             // All 3 must apply
415             //
416             ApplyType applyAnd = new ApplyType();
417             applyAnd.setDescription("return true if all the apply's are true.");
418             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
419             applyAnd.getExpression().add(factory.createApply(timeRange));
420             applyAnd.getExpression().add(factory.createApply(minApply));
421             applyAnd.getExpression().add(factory.createApply(maxApply));
422             //
423             // Add into the condition
424             //
425             condition.setExpression(factory.createApply(applyAnd));
426
427             return condition;
428         }
429         //
430         // At least one of these applies is null. We need at least
431         // two to require the And apply. Otherwise there is no need
432         // for an outer And apply as the single condition can work
433         // on its own.
434         //
435         if (timeRange != null && minApply == null && maxApply == null) {
436             //
437             // Only the time range check is necessary
438             //
439             condition.setExpression(factory.createApply(timeRange));
440         } else if (timeRange == null && minApply != null && maxApply == null) {
441             //
442             // Only the min check is necessary
443             //
444             condition.setExpression(factory.createApply(minApply));
445         } else if (timeRange == null && minApply == null) {
446             //
447             // Only the max check is necessary
448             //
449             condition.setExpression(factory.createApply(maxApply));
450         } else {
451             //
452             // Ok we will need an outer And and have at least the
453             // time range and either min or max check
454             //
455             ApplyType applyAnd = new ApplyType();
456             applyAnd.setDescription("return true if all the apply's are true.");
457             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
458             if (timeRange != null) {
459                 applyAnd.getExpression().add(factory.createApply(timeRange));
460             }
461             if (minApply != null) {
462                 applyAnd.getExpression().add(factory.createApply(minApply));
463             }
464             if (maxApply != null) {
465                 applyAnd.getExpression().add(factory.createApply(maxApply));
466             }
467             //
468             // Add into the condition
469             //
470             condition.setExpression(factory.createApply(applyAnd));
471         }
472         return condition;
473     }
474
475     private static RuleType generateBlacklistPermit(String policyName, Map<String, Object> properties) {
476         //
477         // Generate target
478         //
479         if (! properties.containsKey(FIELD_TARGET)) {
480             LOGGER.error("Missing target for blacklist policy");
481             return null;
482         }
483         final ApplyType targetApply = generateTargetApply(properties.get(FIELD_TARGET));
484         //
485         // Get the properties that are common among guards
486         //
487         String guardActiveStart = null;
488         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
489             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
490         }
491         String guardActiveEnd = null;
492         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
493             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
494         }
495         //
496         // Generate the time in range
497         //
498         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
499         //
500         // Create our rule
501         //
502         RuleType permit = new RuleType();
503         permit.setDescription(DESC_DEFAULT);
504         permit.setRuleId(policyName + ID_RULE);
505         permit.setEffect(EffectType.PERMIT);
506         permit.setTarget(new TargetType());
507         //
508         // Create our condition
509         //
510         ObjectFactory factory = new ObjectFactory();
511         ApplyType innerApply;
512         if (timeRange != null) {
513             ApplyType applyAnd = new ApplyType();
514             applyAnd.setDescription("Combine the timeRange with target to create AND");
515             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
516             applyAnd.getExpression().add(factory.createApply(timeRange));
517             applyAnd.getExpression().add(factory.createApply(targetApply));
518             //
519             // Now we need to NOT this so the permit happens
520             //
521             ApplyType applyNot = new ApplyType();
522             applyNot.setDescription("This should be false for a  permit.");
523             applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue());
524             applyNot.getExpression().add(factory.createApply(applyAnd));
525             innerApply = applyNot;
526         } else {
527             //
528             // Just the target is needed
529             //
530             ApplyType applyNot = new ApplyType();
531             applyNot.setDescription("This should be false for a  permit.");
532             applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue());
533             applyNot.getExpression().add(factory.createApply(targetApply));
534             innerApply = applyNot;
535         }
536         //
537         // Create our condition
538         //
539         final ConditionType condition = new ConditionType();
540         //
541         // Add into the condition
542         //
543         condition.setExpression(factory.createApply(innerApply));
544         //
545         // Add the condition
546         //
547         permit.setCondition(condition);
548         return permit;
549     }
550
551     private static ApplyType generateTimeInRange(String start, String end) {
552         if (start == null || end == null) {
553             LOGGER.warn("Missing time range start {} end {}", start, end);
554             return null;
555         }
556         if (start.isEmpty() || end.isEmpty()) {
557             LOGGER.warn("Empty time range start {} end {}", start, end);
558             return null;
559         }
560
561         AttributeDesignatorType designator = new AttributeDesignatorType();
562         designator.setAttributeId(XACML3.ID_ENVIRONMENT_CURRENT_TIME.stringValue());
563         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT.stringValue());
564         designator.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
565
566         AttributeValueType valueStart = new AttributeValueType();
567         valueStart.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
568         valueStart.getContent().add(start);
569
570         AttributeValueType valueEnd = new AttributeValueType();
571         valueEnd.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
572         valueEnd.getContent().add(end);
573
574         ObjectFactory factory = new ObjectFactory();
575
576         ApplyType applyOneAndOnly = new ApplyType();
577         applyOneAndOnly.setDescription("Unbag the current time");
578         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_TIME_ONE_AND_ONLY.stringValue());
579         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
580
581         ApplyType applyTimeInRange = new ApplyType();
582         applyTimeInRange.setDescription("return true if current time is in range.");
583         applyTimeInRange.setFunctionId(XACML3.ID_FUNCTION_TIME_IN_RANGE.stringValue());
584         applyTimeInRange.getExpression().add(factory.createApply(applyOneAndOnly));
585         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueStart));
586         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueEnd));
587
588         return applyTimeInRange;
589     }
590
591     private static ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) {
592         AttributeDesignatorType designator = new AttributeDesignatorType();
593         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue());
594         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
595         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
596         //
597         // Setup issuer
598         //
599         String issuer = ToscaDictionary.GUARD_ISSUER_PREFIX
600             + CountRecentOperationsPip.ISSUER_NAME
601             + ":tw:" + timeWindow + ":" + timeUnits;
602         designator.setIssuer(issuer);
603
604         AttributeValueType valueLimit = new AttributeValueType();
605         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
606         //
607         // Yes really use toString(), the marshaller will
608         // throw an exception if this is an integer object
609         // and not a string.
610         //
611         valueLimit.getContent().add(limit.toString());
612
613         ObjectFactory factory = new ObjectFactory();
614
615         ApplyType applyOneAndOnly = new ApplyType();
616         applyOneAndOnly.setDescription("Unbag the limit");
617         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
618         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
619
620         ApplyType applyLessThan = new ApplyType();
621         applyLessThan.setDescription("return true if current count is less than.");
622         applyLessThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN.stringValue());
623         applyLessThan.getExpression().add(factory.createApply(applyOneAndOnly));
624         applyLessThan.getExpression().add(factory.createAttributeValue(valueLimit));
625
626         return applyLessThan;
627     }
628
629     private static ApplyType generateMinCheck(Integer min) {
630         if (min == null) {
631             return null;
632         }
633         AttributeDesignatorType designator = new AttributeDesignatorType();
634         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
635         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
636         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
637         //
638         //
639         //
640         AttributeValueType valueLimit = new AttributeValueType();
641         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
642         //
643         // Yes really use toString(), the marshaller will
644         // throw an exception if this is an integer object
645         // and not a string.
646         //
647         valueLimit.getContent().add(min.toString());
648         ObjectFactory factory = new ObjectFactory();
649
650         ApplyType applyOneAndOnly = new ApplyType();
651         applyOneAndOnly.setDescription("Unbag the min");
652         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
653         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
654
655         ApplyType applyGreaterThanEqual = new ApplyType();
656         applyGreaterThanEqual.setDescription("return true if current count is greater than or equal.");
657         applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue());
658         applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
659         applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
660
661         return applyGreaterThanEqual;
662     }
663
664     private static ApplyType generateMaxCheck(Integer max) {
665         if (max == null) {
666             return null;
667         }
668         AttributeDesignatorType designator = new AttributeDesignatorType();
669         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
670         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
671         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
672         //
673         //
674         //
675         AttributeValueType valueLimit = new AttributeValueType();
676         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
677         //
678         // Yes really use toString(), the marshaller will
679         // throw an exception if this is an integer object
680         // and not a string.
681         //
682         valueLimit.getContent().add(max.toString());
683         ObjectFactory factory = new ObjectFactory();
684
685         ApplyType applyOneAndOnly = new ApplyType();
686         applyOneAndOnly.setDescription("Unbag the min");
687         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
688         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
689
690         ApplyType applyLessThanEqual = new ApplyType();
691         applyLessThanEqual.setDescription("return true if current count is less than or equal.");
692         applyLessThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN_OR_EQUAL.stringValue());
693         applyLessThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
694         applyLessThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
695
696         return applyLessThanEqual;
697     }
698
699     @SuppressWarnings("unchecked")
700     private static ApplyType generateTargetApply(Object targetObject) {
701         ObjectFactory factory = new ObjectFactory();
702         //
703         // Create a bag of values
704         //
705         ApplyType applyStringBag = new ApplyType();
706         applyStringBag.setDescription("Bag the target values");
707         applyStringBag.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG.stringValue());
708         if (targetObject instanceof Collection) {
709             for (Object target : ((Collection<Object>) targetObject)) {
710                 if (! (target instanceof String)) {
711                     LOGGER.error("Collection of unsupported objects {}", target.getClass());
712                     return null;
713                 }
714                 AttributeValueType value = new AttributeValueType();
715                 value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
716                 value.getContent().add(target.toString());
717                 applyStringBag.getExpression().add(factory.createAttributeValue(value));
718             }
719         } else if (targetObject instanceof String) {
720             AttributeValueType value = new AttributeValueType();
721             value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
722             value.getContent().add(targetObject.toString());
723             applyStringBag.getExpression().add(factory.createAttributeValue(value));
724         } else {
725             LOGGER.warn("Unsupported object for target {}", targetObject.getClass());
726             return null;
727         }
728         //
729         // Create our designator
730         //
731         AttributeDesignatorType designator = new AttributeDesignatorType();
732         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_TARGETID.stringValue());
733         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
734         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
735         //
736         // Create apply for our AnyOf
737         //
738         ApplyType applyAnyOf = new ApplyType();
739         applyAnyOf.setDescription("Find designator as anyof the possible values");
740         applyAnyOf.setFunctionId(XACML3.ID_FUNCTION_ANY_OF.stringValue());
741         applyAnyOf.getExpression().add(factory.createAttributeDesignator(designator));
742         applyAnyOf.getExpression().add(factory.createApply(applyStringBag));
743         return applyAnyOf;
744     }
745
746     private static Integer parseInteger(String strInteger) {
747         Integer theInt = null;
748         try {
749             theInt = Integer.parseInt(strInteger);
750         } catch (NumberFormatException e) {
751             LOGGER.warn("Expecting an integer", e);
752             try {
753                 Double dblLimit = Double.parseDouble(strInteger);
754                 theInt = dblLimit.intValue();
755             } catch (NumberFormatException e1) {
756                 LOGGER.error("Failed to parse expected integer as a double", e);
757                 return null;
758             }
759         }
760         return theInt;
761     }
762
763     @SuppressWarnings("unused")
764     private static AdviceExpressionsType generateRequestIdAdvice() {
765         AdviceExpressionType adviceExpression = new AdviceExpressionType();
766         adviceExpression.setAppliesTo(EffectType.PERMIT);
767         adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_GUARD.stringValue());
768
769         AttributeDesignatorType designator = new AttributeDesignatorType();
770         designator.setAttributeId(ToscaDictionary.ID_SUBJECT_GUARD_REQUESTID.stringValue());
771         designator.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
772         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
773
774         AttributeAssignmentExpressionType assignment = new AttributeAssignmentExpressionType();
775         assignment.setAttributeId(ToscaDictionary.ID_ADVICE_GUARD_REQUESTID.stringValue());
776         assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
777         assignment.setExpression(new ObjectFactory().createAttributeDesignator(designator));
778
779         adviceExpression.getAttributeAssignmentExpression().add(assignment);
780
781         AdviceExpressionsType adviceExpressions = new AdviceExpressionsType();
782         adviceExpressions.getAdviceExpression().add(adviceExpression);
783
784         return adviceExpressions;
785     }
786 }