bump poms to 2.1.4-SNAPSHOT
[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
72     public LegacyGuardTranslator() {
73         super();
74     }
75
76     @Override
77     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
78         //
79         // Policy name should be at the root
80         //
81         String policyName = toscaPolicy.getMetadata().get("policy-id");
82         //
83         // Set it as the policy ID
84         //
85         PolicyType newPolicyType = new PolicyType();
86         newPolicyType.setPolicyId(policyName);
87         //
88         // Optional description
89         //
90         newPolicyType.setDescription(toscaPolicy.getDescription());
91         //
92         // There should be a metadata section
93         //
94         this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
95         //
96         // Set the combining rule
97         //
98         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
99         //
100         // Generate the TargetType - add true if not blacklist
101         //
102         newPolicyType.setTarget(this.generateTargetType(toscaPolicy.getProperties(),
103                 ! "onap.policies.controlloop.guard.Blacklist".equals(toscaPolicy.getType())));
104         //
105         // Now create the Permit Rule
106         //
107         RuleType rule = generatePermitRule(policyName, toscaPolicy.getType(), toscaPolicy.getProperties());
108         //
109         // Check if we were able to create the rule
110         //
111         if (rule == null) {
112             LOGGER.error("Failed to create rule");
113             return null;
114         }
115         //
116         // Add the rule to the policy
117         //
118         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
119         //
120         // Return our new policy
121         //
122         return newPolicyType;
123     }
124
125     @Override
126     public Request convertRequest(DecisionRequest request) {
127         LOGGER.info("Converting Request {}", request);
128         try {
129             return RequestParser.parseRequest(LegacyGuardPolicyRequest.createInstance(request));
130         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
131             LOGGER.error("Failed to convert DecisionRequest: {}", e);
132         }
133         //
134         // TODO throw exception
135         //
136         return null;
137     }
138
139     @Override
140     public DecisionResponse convertResponse(Response xacmlResponse) {
141         LOGGER.info("Converting Response {}", xacmlResponse);
142         DecisionResponse decisionResponse = new DecisionResponse();
143         //
144         // Iterate through all the results
145         //
146         for (Result xacmlResult : xacmlResponse.getResults()) {
147             //
148             // Check the result
149             //
150             if (xacmlResult.getDecision() == Decision.PERMIT) {
151                 //
152                 // Just simply return a Permit response
153                 //
154                 decisionResponse.setStatus(Decision.PERMIT.toString());
155             }
156             if (xacmlResult.getDecision() == Decision.DENY) {
157                 //
158                 // Just simply return a Deny response
159                 //
160                 decisionResponse.setStatus(Decision.DENY.toString());
161             }
162             if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
163                 //
164                 // There is no guard policy, so we return a permit
165                 //
166                 decisionResponse.setStatus(Decision.PERMIT.toString());
167             }
168         }
169
170         return decisionResponse;
171     }
172
173     /**
174      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
175      *
176      * @param policy Policy Object to store the metadata
177      * @param map The Metadata TOSCA Map
178      * @return Same Policy Object
179      * @throws ToscaPolicyConversionException If there is something missing from the metadata
180      */
181     protected PolicyType fillMetadataSection(PolicyType policy,
182             Map<String, String> map) throws ToscaPolicyConversionException {
183         if (! map.containsKey("policy-id")) {
184             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
185         } else {
186             //
187             // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
188             //
189         }
190         if (! map.containsKey("policy-version")) {
191             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
192         } else {
193             //
194             // Add in the Policy Version
195             //
196             policy.setVersion(map.get("policy-version").toString());
197         }
198         return policy;
199     }
200
201     protected TargetType generateTargetType(Map<String, Object> properties, boolean addTargets) {
202         //
203         // Go through potential properties
204         //
205         AllOfType allOf = new AllOfType();
206         if (properties.containsKey("actor")) {
207             addMatch(allOf, properties.get("actor"), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
208         }
209         if (properties.containsKey("recipe")) {
210             addMatch(allOf, properties.get("recipe"), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
211         }
212         if (addTargets) {
213             if (properties.containsKey("targets")) {
214                 addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
215             }
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("Default is to PERMIT if the policy matches.");
337         permit.setRuleId(policyName + ":rule");
338         permit.setEffect(EffectType.PERMIT);
339         permit.setTarget(new TargetType());
340         //
341         // Add the condition
342         //
343         permit.setCondition(condition);
344         //
345         // TODO Add the advice - Is the request id needed to be returned?
346         //
347         // permit.setAdviceExpressions(adviceExpressions);
348         //
349         // Done
350         //
351         return permit;
352     }
353
354     private static RuleType generateMinMaxPermit(String policyName, Map<String, Object> properties) {
355         //
356         // Get the properties that are common among guards
357         //
358         String guardActiveStart = null;
359         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
360             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
361         }
362         String guardActiveEnd = null;
363         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
364             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
365         }
366         //
367         // Generate the time in range
368         //
369         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
370         //
371         // See if its possible to generate a count
372         //
373         Integer min = null;
374         if (properties.containsKey("min")) {
375             min = parseInteger(properties.get("min").toString());
376         }
377         Integer max = null;
378         if (properties.containsKey("max")) {
379             max = parseInteger(properties.get("max").toString());
380         }
381         final ApplyType minApply = generateMinCheck(min);
382         final ApplyType maxApply = generateMaxCheck(max);
383         //
384         // Make sure we have at least something to check here,
385         // otherwise there really is no point to this policy.
386         //
387         if (timeRange == null && minApply == null && maxApply == null) {
388             return null;
389         }
390         //
391         // Create our rule
392         //
393         RuleType permit = new RuleType();
394         permit.setDescription("Default is to PERMIT if the policy matches.");
395         permit.setRuleId(policyName + ":rule");
396         permit.setEffect(EffectType.PERMIT);
397         permit.setTarget(new TargetType());
398         //
399         // Create our condition
400         //
401         final ConditionType condition = new ConditionType();
402         //
403         // Check if we have all the fields (this can be a little
404         // ugly) but the ultimate goal is to simplify the policy
405         // condition to only check for necessary attributes.
406         //
407         ObjectFactory factory = new ObjectFactory();
408         if (timeRange != null && minApply != null && maxApply != null) {
409             //
410             // All 3 must apply
411             //
412             ApplyType applyAnd = new ApplyType();
413             applyAnd.setDescription("return true if all the apply's are true.");
414             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
415             applyAnd.getExpression().add(factory.createApply(timeRange));
416             applyAnd.getExpression().add(factory.createApply(minApply));
417             applyAnd.getExpression().add(factory.createApply(maxApply));
418             //
419             // Add into the condition
420             //
421             condition.setExpression(factory.createApply(applyAnd));
422         } else {
423             //
424             // At least one of these applies is null. We need at least
425             // two to require the And apply. Otherwise there is no need
426             // for an outer And apply as the single condition can work
427             // on its own.
428             //
429             if (timeRange != null && minApply == null && maxApply == null) {
430                 //
431                 // Only the time range check is necessary
432                 //
433                 condition.setExpression(factory.createApply(timeRange));
434             } else if (timeRange == null && minApply != null && maxApply == null) {
435                 //
436                 // Only the min check is necessary
437                 //
438                 condition.setExpression(factory.createApply(minApply));
439             } else if (timeRange == null && minApply == null) {
440                 //
441                 // Only the max check is necessary
442                 //
443                 condition.setExpression(factory.createApply(maxApply));
444             } else {
445                 //
446                 // Ok we will need an outer And and have at least the
447                 // time range and either min or max check
448                 //
449                 ApplyType applyAnd = new ApplyType();
450                 applyAnd.setDescription("return true if all the apply's are true.");
451                 applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
452                 if (timeRange != null) {
453                     applyAnd.getExpression().add(factory.createApply(timeRange));
454                 }
455                 if (minApply != null) {
456                     applyAnd.getExpression().add(factory.createApply(minApply));
457                 }
458                 if (maxApply != null) {
459                     applyAnd.getExpression().add(factory.createApply(maxApply));
460                 }
461                 //
462                 // Add into the condition
463                 //
464                 condition.setExpression(factory.createApply(applyAnd));
465             }
466         }
467         //
468         // Add the condition
469         //
470         permit.setCondition(condition);
471         //
472         // TODO Add the advice - Is the request id needed to be returned?
473         //
474         // permit.setAdviceExpressions(adviceExpressions);
475         //
476         // Done
477         //
478         return permit;
479     }
480
481     private static RuleType generateBlacklistPermit(String policyName, Map<String, Object> properties) {
482         //
483         // Generate target
484         //
485         if (! properties.containsKey(FIELD_TARGET)) {
486             LOGGER.error("Missing target for blacklist policy");
487             return null;
488         }
489         final ApplyType targetApply = generateTargetApply(properties.get(FIELD_TARGET));
490         //
491         // Get the properties that are common among guards
492         //
493         String guardActiveStart = null;
494         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
495             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
496         }
497         String guardActiveEnd = null;
498         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
499             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
500         }
501         //
502         // Generate the time in range
503         //
504         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
505         //
506         // Create our rule
507         //
508         RuleType permit = new RuleType();
509         permit.setDescription("Default is to PERMIT if the policy matches.");
510         permit.setRuleId(policyName + ":rule");
511         permit.setEffect(EffectType.PERMIT);
512         permit.setTarget(new TargetType());
513         //
514         // Create our condition
515         //
516         ObjectFactory factory = new ObjectFactory();
517         ApplyType innerApply;
518         if (timeRange != null) {
519             ApplyType applyAnd = new ApplyType();
520             applyAnd.setDescription("Combine the timeRange with target to create AND");
521             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
522             applyAnd.getExpression().add(factory.createApply(timeRange));
523             applyAnd.getExpression().add(factory.createApply(targetApply));
524             //
525             // Now we need to NOT this so the permit happens
526             //
527             ApplyType applyNot = new ApplyType();
528             applyNot.setDescription("This should be false for a  permit.");
529             applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue());
530             applyNot.getExpression().add(factory.createApply(applyAnd));
531             innerApply = applyNot;
532         } else {
533             //
534             // Just the target is needed
535             //
536             ApplyType applyNot = new ApplyType();
537             applyNot.setDescription("This should be false for a  permit.");
538             applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue());
539             applyNot.getExpression().add(factory.createApply(targetApply));
540             innerApply = applyNot;
541         }
542         //
543         // Create our condition
544         //
545         final ConditionType condition = new ConditionType();
546         //
547         // Add into the condition
548         //
549         condition.setExpression(factory.createApply(innerApply));
550         //
551         // Add the condition
552         //
553         permit.setCondition(condition);
554         return permit;
555     }
556
557     private static ApplyType generateTimeInRange(String start, String end) {
558         if (start == null || end == null) {
559             LOGGER.warn("Missing time range start {} end {}", start, end);
560             return null;
561         }
562         if (start.isEmpty() || end.isEmpty()) {
563             LOGGER.warn("Empty time range start {} end {}", start, end);
564             return null;
565         }
566
567         AttributeDesignatorType designator = new AttributeDesignatorType();
568         designator.setAttributeId(XACML3.ID_ENVIRONMENT_CURRENT_TIME.stringValue());
569         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT.stringValue());
570         designator.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
571
572         AttributeValueType valueStart = new AttributeValueType();
573         valueStart.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
574         valueStart.getContent().add(start);
575
576         AttributeValueType valueEnd = new AttributeValueType();
577         valueEnd.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
578         valueEnd.getContent().add(end);
579
580         ObjectFactory factory = new ObjectFactory();
581
582         ApplyType applyOneAndOnly = new ApplyType();
583         applyOneAndOnly.setDescription("Unbag the current time");
584         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_TIME_ONE_AND_ONLY.stringValue());
585         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
586
587         ApplyType applyTimeInRange = new ApplyType();
588         applyTimeInRange.setDescription("return true if current time is in range.");
589         applyTimeInRange.setFunctionId(XACML3.ID_FUNCTION_TIME_IN_RANGE.stringValue());
590         applyTimeInRange.getExpression().add(factory.createApply(applyOneAndOnly));
591         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueStart));
592         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueEnd));
593
594         return applyTimeInRange;
595     }
596
597     private static ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) {
598         AttributeDesignatorType designator = new AttributeDesignatorType();
599         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue());
600         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
601         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
602         //
603         // Setup issuer
604         //
605         String issuer = ToscaDictionary.GUARD_ISSUER_PREFIX
606             + CountRecentOperationsPip.ISSUER_NAME
607             + ":tw:" + timeWindow + ":" + timeUnits;
608         designator.setIssuer(issuer);
609
610         AttributeValueType valueLimit = new AttributeValueType();
611         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
612         //
613         // Yes really use toString(), the marshaller will
614         // throw an exception if this is an integer object
615         // and not a string.
616         //
617         valueLimit.getContent().add(limit.toString());
618
619         ObjectFactory factory = new ObjectFactory();
620
621         ApplyType applyOneAndOnly = new ApplyType();
622         applyOneAndOnly.setDescription("Unbag the limit");
623         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
624         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
625
626         ApplyType applyLessThan = new ApplyType();
627         applyLessThan.setDescription("return true if current count is less than.");
628         applyLessThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN.stringValue());
629         applyLessThan.getExpression().add(factory.createApply(applyOneAndOnly));
630         applyLessThan.getExpression().add(factory.createAttributeValue(valueLimit));
631
632         return applyLessThan;
633     }
634
635     private static ApplyType generateMinCheck(Integer min) {
636         if (min == null) {
637             return null;
638         }
639         AttributeDesignatorType designator = new AttributeDesignatorType();
640         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
641         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
642         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
643         //
644         //
645         //
646         AttributeValueType valueLimit = new AttributeValueType();
647         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
648         //
649         // Yes really use toString(), the marshaller will
650         // throw an exception if this is an integer object
651         // and not a string.
652         //
653         valueLimit.getContent().add(min.toString());
654         ObjectFactory factory = new ObjectFactory();
655
656         ApplyType applyOneAndOnly = new ApplyType();
657         applyOneAndOnly.setDescription("Unbag the min");
658         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
659         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
660
661         ApplyType applyGreaterThanEqual = new ApplyType();
662         applyGreaterThanEqual.setDescription("return true if current count is greater than or equal.");
663         applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue());
664         applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
665         applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
666
667         return applyGreaterThanEqual;
668     }
669
670     private static ApplyType generateMaxCheck(Integer max) {
671         if (max == null) {
672             return null;
673         }
674         AttributeDesignatorType designator = new AttributeDesignatorType();
675         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
676         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
677         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
678         //
679         //
680         //
681         AttributeValueType valueLimit = new AttributeValueType();
682         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
683         //
684         // Yes really use toString(), the marshaller will
685         // throw an exception if this is an integer object
686         // and not a string.
687         //
688         valueLimit.getContent().add(max.toString());
689         ObjectFactory factory = new ObjectFactory();
690
691         ApplyType applyOneAndOnly = new ApplyType();
692         applyOneAndOnly.setDescription("Unbag the min");
693         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
694         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
695
696         ApplyType applyLessThanEqual = new ApplyType();
697         applyLessThanEqual.setDescription("return true if current count is less than or equal.");
698         applyLessThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN_OR_EQUAL.stringValue());
699         applyLessThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
700         applyLessThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
701
702         return applyLessThanEqual;
703     }
704
705     @SuppressWarnings("unchecked")
706     private static ApplyType generateTargetApply(Object targetObject) {
707         ObjectFactory factory = new ObjectFactory();
708         //
709         // Create a bag of values
710         //
711         ApplyType applyStringBag = new ApplyType();
712         applyStringBag.setDescription("Bag the target values");
713         applyStringBag.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG.stringValue());
714         if (targetObject instanceof Collection) {
715             for (Object target : ((Collection<Object>) targetObject)) {
716                 if (! (target instanceof String)) {
717                     LOGGER.error("Collection of unsupported objects {}", target.getClass());
718                     return null;
719                 }
720                 AttributeValueType value = new AttributeValueType();
721                 value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
722                 value.getContent().add(target.toString());
723                 applyStringBag.getExpression().add(factory.createAttributeValue(value));
724             }
725         } else if (targetObject instanceof String) {
726             AttributeValueType value = new AttributeValueType();
727             value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
728             value.getContent().add(targetObject.toString());
729             applyStringBag.getExpression().add(factory.createAttributeValue(value));
730         } else {
731             LOGGER.warn("Unsupported object for target {}", targetObject.getClass());
732             return null;
733         }
734         //
735         // Create our designator
736         //
737         AttributeDesignatorType designator = new AttributeDesignatorType();
738         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_TARGETID.stringValue());
739         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
740         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
741         //
742         // Create apply for our AnyOf
743         //
744         ApplyType applyAnyOf = new ApplyType();
745         applyAnyOf.setDescription("Find designator as anyof the possible values");
746         applyAnyOf.setFunctionId(XACML3.ID_FUNCTION_ANY_OF.stringValue());
747         applyAnyOf.getExpression().add(factory.createAttributeDesignator(designator));
748         applyAnyOf.getExpression().add(factory.createApply(applyStringBag));
749         return applyAnyOf;
750     }
751
752     private static Integer parseInteger(String strInteger) {
753         Integer theInt = null;
754         try {
755             theInt = Integer.parseInt(strInteger);
756         } catch (NumberFormatException e) {
757             LOGGER.warn("Expecting an integer", e);
758             try {
759                 Double dblLimit = Double.parseDouble(strInteger);
760                 theInt = dblLimit.intValue();
761             } catch (NumberFormatException e1) {
762                 LOGGER.error("Failed to parse expected integer as a double", e);
763                 return null;
764             }
765         }
766         return theInt;
767     }
768
769     private static AdviceExpressionsType generateRequestIdAdvice() {
770         AdviceExpressionType adviceExpression = new AdviceExpressionType();
771         adviceExpression.setAppliesTo(EffectType.PERMIT);
772         adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_GUARD.stringValue());
773
774         AttributeDesignatorType designator = new AttributeDesignatorType();
775         designator.setAttributeId(ToscaDictionary.ID_SUBJECT_GUARD_REQUESTID.stringValue());
776         designator.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
777         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
778
779         AttributeAssignmentExpressionType assignment = new AttributeAssignmentExpressionType();
780         assignment.setAttributeId(ToscaDictionary.ID_ADVICE_GUARD_REQUESTID.stringValue());
781         assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
782         assignment.setExpression(new ObjectFactory().createAttributeDesignator(designator));
783
784         adviceExpression.getAttributeAssignmentExpression().add(assignment);
785
786         AdviceExpressionsType adviceExpressions = new AdviceExpressionsType();
787         adviceExpressions.getAdviceExpression().add(adviceExpression);
788
789         return adviceExpressions;
790     }
791 }