Merge "Use Policy Translator abstract class"
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdCombinedPolicyResultsTranslator.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.pdp.xacml.application.common.std;
24
25 import com.att.research.xacml.api.AttributeAssignment;
26 import com.att.research.xacml.api.DataTypeException;
27 import com.att.research.xacml.api.Decision;
28 import com.att.research.xacml.api.Obligation;
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.annotations.RequestParser;
34 import com.att.research.xacml.util.XACMLPolicyWriter;
35 import com.google.gson.Gson;
36
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Map.Entry;
43
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
52 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
53 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
54 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
55
56 import org.json.JSONObject;
57 import org.onap.policy.models.decisions.concepts.DecisionRequest;
58 import org.onap.policy.models.decisions.concepts.DecisionResponse;
59 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
60 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
61 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
62 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator {
67
68     private static final Logger LOGGER = LoggerFactory.getLogger(StdCombinedPolicyResultsTranslator.class);
69
70     public StdCombinedPolicyResultsTranslator() {
71         super();
72     }
73
74     @SuppressWarnings("unchecked")
75     @Override
76     public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject)
77             throws ToscaPolicyConversionException {
78         //
79         // Our return object
80         //
81         List<PolicyType> scannedPolicies = new ArrayList<>();
82         //
83         // Iterate each of the Policies
84         //
85         List<Object> policies = (List<Object>) toscaObject.get("policies");
86         for (Object policyObject : policies) {
87             //
88             // Get the contents
89             //
90             LOGGER.debug("Found policy {}", policyObject.getClass());
91             Map<String, Object> policyContents = (Map<String, Object>) policyObject;
92             for (Entry<String, Object> entrySet : policyContents.entrySet()) {
93                 LOGGER.debug("Entry set {}", entrySet);
94                 //
95                 // Convert this policy
96                 //
97                 PolicyType policy = this.convertPolicy(entrySet);
98                 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
99                     XACMLPolicyWriter.writePolicyFile(os, policy);
100                     LOGGER.debug("{}", os);
101                 } catch (IOException e) {
102                     LOGGER.error("Failed to convert {}", e);
103                 }
104                 //
105                 // Convert and add in the new policy
106                 //
107                 scannedPolicies.add(policy);
108             }
109         }
110
111         return scannedPolicies;
112     }
113
114     @Override
115     public Request convertRequest(DecisionRequest request) {
116         LOGGER.debug("Converting Request {}", request);
117         try {
118             return RequestParser.parseRequest(StdCombinedPolicyRequest.createInstance(request));
119         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
120             LOGGER.error("Failed to convert DecisionRequest: {}", e);
121         }
122         //
123         // TODO throw exception
124         //
125         return null;
126     }
127
128     @Override
129     public DecisionResponse convertResponse(Response xacmlResponse) {
130         LOGGER.debug("Converting Response {}", xacmlResponse);
131         DecisionResponse decisionResponse = new DecisionResponse();
132         //
133         // Iterate through all the results
134         //
135         for (Result xacmlResult : xacmlResponse.getResults()) {
136             //
137             // Check the result
138             //
139             if (xacmlResult.getDecision() == Decision.PERMIT) {
140                 //
141                 // Setup policies
142                 //
143                 decisionResponse.setPolicies(new ArrayList<>());
144                 //
145                 // Go through obligations
146                 //
147                 for (Obligation obligation : xacmlResult.getObligations()) {
148                     LOGGER.debug("Obligation: {}", obligation);
149                     for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
150                         LOGGER.debug("Attribute Assignment: {}", assignment);
151                         //
152                         // We care about the content attribute
153                         //
154                         if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS
155                                 .equals(assignment.getAttributeId())) {
156                             //
157                             // The contents are in Json form
158                             //
159                             Object stringContents = assignment.getAttributeValue().getValue();
160                             if (LOGGER.isDebugEnabled()) {
161                                 LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
162                             }
163                             //
164                             // Let's parse it into a map using Gson
165                             //
166                             Gson gson = new Gson();
167                             @SuppressWarnings("unchecked")
168                             Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
169                             decisionResponse.getPolicies().add(result);
170                         }
171                     }
172                 }
173             } else {
174                 decisionResponse.setErrorMessage("A better error message");
175             }
176         }
177
178         return decisionResponse;
179     }
180
181     @SuppressWarnings("unchecked")
182     protected PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
183         //
184         // Policy name should be at the root
185         //
186         String policyName = entrySet.getKey();
187         Map<String, Object> policyDefinition = (Map<String, Object>) entrySet.getValue();
188         //
189         // Set it as the policy ID
190         //
191         PolicyType newPolicyType = new PolicyType();
192         newPolicyType.setPolicyId(policyName);
193         //
194         // Optional description
195         //
196         if (policyDefinition.containsKey("description")) {
197             newPolicyType.setDescription(policyDefinition.get("description").toString());
198         }
199         //
200         // There should be a metadata section
201         //
202         if (! policyDefinition.containsKey("metadata")) {
203             throw new ToscaPolicyConversionException(policyName + " missing metadata section");
204         }
205         this.fillMetadataSection(newPolicyType,
206                 (Map<String, Object>) policyDefinition.get("metadata"));
207         //
208         // Set the combining rule
209         //
210         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
211         //
212         // Generate the TargetType
213         //
214         //
215         // There should be a metadata section
216         //
217         if (! policyDefinition.containsKey("type")) {
218             throw new ToscaPolicyConversionException(policyName + " missing type value");
219         }
220         if (! policyDefinition.containsKey("version")) {
221             throw new ToscaPolicyConversionException(policyName + " missing version value");
222         }
223         TargetType target = this.generateTargetType(policyName,
224                 policyDefinition.get("type").toString(),
225                 policyDefinition.get("version").toString());
226         newPolicyType.setTarget(target);
227         //
228         // Now create the Permit Rule
229         // No target since the policy has a target
230         // With obligations.
231         //
232         RuleType rule = new RuleType();
233         rule.setDescription("Default is to PERMIT if the policy matches.");
234         rule.setRuleId(policyName + ":rule");
235         rule.setEffect(EffectType.PERMIT);
236         rule.setTarget(new TargetType());
237         //
238         // Now represent the policy as Json
239         //
240         JSONObject jsonObligation = new JSONObject();
241         jsonObligation.put(policyName, policyDefinition);
242         addObligation(rule, jsonObligation);
243         //
244         // Add the rule to the policy
245         //
246         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
247         //
248         // Return our new policy
249         //
250         return newPolicyType;
251     }
252
253     /**
254      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
255      *
256      * @param policy Policy Object to store the metadata
257      * @param metadata The Metadata TOSCA Map
258      * @return Same Policy Object
259      * @throws ToscaPolicyConversionException If there is something missing from the metadata
260      */
261     protected PolicyType fillMetadataSection(PolicyType policy,
262             Map<String, Object> metadata) throws ToscaPolicyConversionException {
263         if (! metadata.containsKey("policy-id")) {
264             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
265         } else {
266             //
267             // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
268             //
269         }
270         if (! metadata.containsKey("policy-version")) {
271             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
272         } else {
273             //
274             // Add in the Policy Version
275             //
276             policy.setVersion(metadata.get("policy-version").toString());
277         }
278         return policy;
279     }
280
281     protected TargetType generateTargetType(String policyId, String policyType, String policyTypeVersion) {
282         //
283         // Create all the match's that are possible
284         //
285         // This is for the Policy Id
286         //
287         MatchType matchPolicyId = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
288                 XACML3.ID_FUNCTION_STRING_EQUAL,
289                 policyId,
290                 XACML3.ID_DATATYPE_STRING,
291                 ToscaDictionary.ID_RESOURCE_POLICY_ID,
292                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
293         //
294         // This is for the Policy Type
295         //
296         MatchType matchPolicyType = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
297                 XACML3.ID_FUNCTION_STRING_EQUAL,
298                 policyType,
299                 XACML3.ID_DATATYPE_STRING,
300                 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
301                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
302         //
303         // This is for the Policy Type version
304         //
305         MatchType matchPolicyTypeVersion = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
306                 XACML3.ID_FUNCTION_STRING_EQUAL,
307                 policyTypeVersion,
308                 XACML3.ID_DATATYPE_STRING,
309                 ToscaDictionary.ID_RESOURCE_POLICY_TYPE_VERSION,
310                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
311         //
312         // This is our outer AnyOf - which is an OR
313         //
314         AnyOfType anyOf = new AnyOfType();
315         //
316         // Create AllOf (AND) of just Policy Id
317         //
318         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyId));
319         //
320         // Create AllOf (AND) of just Policy Type
321         //
322         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType));
323         //
324         // Create AllOf (AND) of Policy Type and Policy Type Version
325         //
326         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType, matchPolicyTypeVersion));
327         //
328         // Now we can create the TargetType, add the top-level anyOf (OR),
329         // and return the value.
330         //
331         TargetType target = new TargetType();
332         target.getAnyOf().add(anyOf);
333         return target;
334     }
335
336     protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) {
337         //
338         // Convert the YAML Policy to JSON Object
339         //
340         if (LOGGER.isDebugEnabled()) {
341             LOGGER.debug("JSON DCAE Policy {}{}", System.lineSeparator(), jsonPolicy);
342         }
343         //
344         // Create an AttributeValue for it
345         //
346         AttributeValueType value = new AttributeValueType();
347         value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
348         value.getContent().add(jsonPolicy.toString());
349         //
350         // Create our AttributeAssignmentExpression where we will
351         // store the contents of the policy in JSON format.
352         //
353         AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType();
354         expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue());
355         ObjectFactory factory = new ObjectFactory();
356         expressionType.setExpression(factory.createAttributeValue(value));
357         //
358         // Create an ObligationExpression for it
359         //
360         ObligationExpressionType obligation = new ObligationExpressionType();
361         obligation.setFulfillOn(EffectType.PERMIT);
362         obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
363         obligation.getAttributeAssignmentExpression().add(expressionType);
364         //
365         // Now we can add it into the rule
366         //
367         ObligationExpressionsType obligations = new ObligationExpressionsType();
368         obligations.getObligationExpression().add(obligation);
369         rule.setObligationExpressions(obligations);
370         return rule;
371     }
372
373 }