Missing support for PolicySetType
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdBaseTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.pdp.xacml.application.common.std;
24
25 import com.att.research.xacml.api.Advice;
26 import com.att.research.xacml.api.Decision;
27 import com.att.research.xacml.api.Obligation;
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 java.util.Collection;
33 import java.util.HashMap;
34 import java.util.Map;
35 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
36 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
47 import org.onap.policy.models.decisions.concepts.DecisionRequest;
48 import org.onap.policy.models.decisions.concepts.DecisionResponse;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
50 import org.onap.policy.pdp.xacml.application.common.OnapObligation;
51 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
52 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
53 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
54 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
55 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public abstract class StdBaseTranslator implements ToscaPolicyTranslator {
60     private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class);
61     private static final ObjectFactory factory = new ObjectFactory();
62
63     public static final String POLICY_ID = "policy-id";
64     public static final String POLICY_VERSION = "policy-version";
65
66     @Override
67     public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
68         throw new ToscaPolicyConversionException("Please override convertPolicy");
69     }
70
71     @Override
72     public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
73         return null;
74     }
75
76     @Override
77     public DecisionResponse convertResponse(Response xacmlResponse) {
78         LOGGER.info("Converting Response {}", xacmlResponse);
79         DecisionResponse decisionResponse = new DecisionResponse();
80         //
81         // Setup policies
82         //
83         decisionResponse.setPolicies(new HashMap<>());
84         //
85         // Iterate through all the results
86         //
87         for (Result xacmlResult : xacmlResponse.getResults()) {
88             //
89             // Check the result
90             //
91             if (xacmlResult.getDecision() == Decision.PERMIT) {
92                 //
93                 // Go through obligations
94                 //
95                 scanObligations(xacmlResult.getObligations(), decisionResponse);
96                 //
97                 // Go through advice
98                 //
99                 scanAdvice(xacmlResult.getAssociatedAdvice(), decisionResponse);
100             } else {
101                 //
102                 // Return error information back
103                 //
104                 decisionResponse.setStatus("error");
105                 decisionResponse.setMessage(xacmlResult.getStatus().getStatusMessage());
106             }
107         }
108
109         return decisionResponse;
110     }
111
112     /**
113      * scanObligations - scans the list of obligations and make appropriate method calls to process
114      * obligations. This method must be overridden and be implemented for the specific application as
115      * obligations may have different expected attributes per application.
116      *
117      * @param obligations Collection of obligation objects
118      * @param decisionResponse DecisionResponse object used to store any results from obligations.
119      */
120     protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse);
121
122     /**
123      * scanAdvice - scans the list of advice and make appropriate call to process the advice. This method
124      * can be overridden for each specific application as advice may have different expected attributes per
125      * application.
126      *
127      * @param advice Collection of Advice objects
128      * @param decisionResponse DecisionResponse object used to store any results from advice.
129      */
130     protected abstract void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse);
131
132     /**
133      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
134      *
135      * @param policy Policy Object to store the metadata
136      * @param map The Metadata TOSCA Map
137      * @return Same Policy Object
138      * @throws ToscaPolicyConversionException If there is something missing from the metadata
139      */
140     protected PolicyType fillMetadataSection(PolicyType policy,
141             Map<String, String> map) throws ToscaPolicyConversionException {
142         //
143         // Ensure the policy-id exists - we don't use it here. It
144         // is saved in the TOSCA Policy Name field.
145         //
146         if (! map.containsKey(POLICY_ID)) {
147             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata " + POLICY_ID);
148         }
149         //
150         // Ensure the policy-version exists
151         //
152         if (! map.containsKey(POLICY_VERSION)) {
153             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata "
154                     + POLICY_VERSION);
155         }
156         //
157         // Add in the Policy Version
158         //
159         policy.setVersion(map.get(POLICY_VERSION));
160         return policy;
161     }
162
163     /**
164      * addObligation - general code to add a json policy as an obligation. Probably could just
165      * return the obligation only instead of adding it directly to a rule/policy/policyset.
166      * But this is fine for now.
167      *
168      * @param <T> RuleType, PolicyType, PolicySetType object
169      * @Param policyId The policy-id
170      * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
171      * @param jsonPolicy JSON String representation of policy.
172      * @param weight Weighting for the policy (optional)
173      * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
174      */
175     protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight,
176             String policyType) {
177         //
178         // Creating obligation for returning policy
179         //
180         LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight,
181                 XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
182         //
183         // Create our OnapObligation
184         //
185         OnapObligation onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight);
186         //
187         // Generate the obligation
188         //
189         ObligationExpressionType obligation = onapObligation.generateObligation();
190         //
191         // Now we can add it into the rule/policy/policyset
192         //
193         ObligationExpressionsType obligations = new ObligationExpressionsType();
194         obligations.getObligationExpression().add(obligation);
195         if (ruleOrPolicy instanceof RuleType) {
196             ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
197         } else if (ruleOrPolicy instanceof PolicyType) {
198             ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
199         } else if (ruleOrPolicy instanceof PolicySetType) {
200             ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
201         } else {
202             LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass());
203         }
204         //
205         // Return as a convenience
206         //
207         return ruleOrPolicy;
208     }
209
210     /**
211      * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
212      * to match on a specific TOSCA Policy Type.
213      *
214      * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
215      * @return AnyOfType object
216      */
217     protected AnyOfType generateAnyOfForPolicyType(String type) {
218         //
219         // Create the match for the policy type
220         //
221         MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
222                 XACML3.ID_FUNCTION_STRING_EQUAL,
223                 type,
224                 XACML3.ID_DATATYPE_STRING,
225                 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
226                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
227         //
228         // Add it to an AnyOfType object
229         //
230         AnyOfType anyOf = new AnyOfType();
231         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
232         //
233         // Return new AnyOfType
234         //
235         return anyOf;
236     }
237
238     /**
239      * generateConditionForPolicyType - create a ConditionType XACML object
240      * that is able to determine if a request specifies a specific policy type
241      * that the policy is created from, only then is the rule applied. If the
242      * request doesn't even care about the policy type (eg it is missing) then
243      * return the rule should not apply.
244      *
245      * @param type PolicyType (eg. onap.policies.Foo
246      * @return ConditionType object
247      */
248     protected ConditionType generateConditionForPolicyType(String type) {
249         //
250         // Create an ApplyType that checks if the request contains the
251         // policy-type attribute
252         //
253         AttributeDesignatorType designator = new AttributeDesignatorType();
254         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
255         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
256         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
257
258         ApplyType applyBagSize = new ApplyType();
259         applyBagSize.setDescription("Get the size of policy-type attributes");
260         applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());
261
262         AttributeValueType valueZero = new AttributeValueType();
263         valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
264         valueZero.getContent().add("0");    // Yes really - represent as a string
265
266         applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));
267
268         ApplyType applyGreaterThan = new ApplyType();
269         applyGreaterThan.setDescription("Does the policy-type attribute exist?");
270         applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());
271
272         applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
273         applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));
274
275         //
276         // Create an apply type that checks the actual value
277         //
278         AttributeValueType value = new AttributeValueType();
279         value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
280         value.getContent().add(type);
281
282         //
283         // Create string-is-in apply - which determines if the policy-type
284         // is in the request bag of resources for policy-type
285         //
286         ApplyType applyIsIn = new ApplyType();
287         applyIsIn.setDescription("Is this policy-type in the list?");
288         applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
289         applyIsIn.getExpression().add(factory.createAttributeValue(value));
290         applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));
291
292         //
293         // Create our outer apply
294         //
295         ApplyType applyOr = new ApplyType();
296         applyOr.setDescription("IF exists and is equal");
297         applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());
298
299         applyOr.getExpression().add(factory.createApply(applyGreaterThan));
300         applyOr.getExpression().add(factory.createApply(applyIsIn));
301
302         //
303         // Finally create the condition
304         //
305         ConditionType condition = new ConditionType();
306
307         condition.setExpression(factory.createApply(applyOr));
308
309         return condition;
310     }
311
312 }