2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.pdp.xacml.application.common.std;
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;
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.List;
43 import java.util.Map.Entry;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
52 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
53 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
54 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
55 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
57 import org.json.JSONObject;
58 import org.onap.policy.models.decisions.concepts.DecisionRequest;
59 import org.onap.policy.models.decisions.concepts.DecisionResponse;
60 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
61 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
62 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
63 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
67 public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator {
69 private static final Logger LOGGER = LoggerFactory.getLogger(StdCombinedPolicyResultsTranslator.class);
71 public StdCombinedPolicyResultsTranslator() {
75 @SuppressWarnings("unchecked")
77 public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject)
78 throws ToscaPolicyConversionException {
82 List<PolicyType> scannedPolicies = new ArrayList<>();
84 // Iterate each of the Policies
86 List<Object> policies = (List<Object>) toscaObject.get("policies");
87 for (Object policyObject : policies) {
91 LOGGER.debug("Found policy {}", policyObject.getClass());
92 Map<String, Object> policyContents = (Map<String, Object>) policyObject;
93 for (Entry<String, Object> entrySet : policyContents.entrySet()) {
94 LOGGER.debug("Entry set {}", entrySet);
96 // Convert this policy
98 PolicyType policy = this.convertPolicy(entrySet);
99 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
100 XACMLPolicyWriter.writePolicyFile(os, policy);
101 LOGGER.debug("{}", os);
102 } catch (IOException e) {
103 LOGGER.error("Failed to convert {}", e);
106 // Convert and add in the new policy
108 scannedPolicies.add(policy);
112 return scannedPolicies;
116 public Request convertRequest(DecisionRequest request) {
117 LOGGER.debug("Converting Request {}", request);
119 return RequestParser.parseRequest(StdCombinedPolicyRequest.createInstance(request));
120 } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
121 LOGGER.error("Failed to convert DecisionRequest: {}", e);
124 // TODO throw exception
130 public DecisionResponse convertResponse(Response xacmlResponse) {
131 LOGGER.debug("Converting Response {}", xacmlResponse);
132 DecisionResponse decisionResponse = new DecisionResponse();
134 // Iterate through all the results
136 for (Result xacmlResult : xacmlResponse.getResults()) {
140 if (xacmlResult.getDecision() == Decision.PERMIT) {
144 decisionResponse.setPolicies(new ArrayList<>());
146 // Go through obligations
148 scanObligations(xacmlResult.getObligations(), decisionResponse);
150 if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
152 // There is no policy
154 decisionResponse.setPolicies(new ArrayList<>());
156 if (xacmlResult.getDecision() == Decision.DENY
157 || xacmlResult.getDecision() == Decision.INDETERMINATE) {
159 // TODO we have to return an ErrorResponse object instead
161 decisionResponse.setStatus("A better error message");
165 return decisionResponse;
168 protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
169 for (Obligation obligation : obligations) {
170 LOGGER.debug("Obligation: {}", obligation);
171 for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
172 LOGGER.debug("Attribute Assignment: {}", assignment);
174 // We care about the content attribute
176 if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS
177 .equals(assignment.getAttributeId())) {
179 // The contents are in Json form
181 Object stringContents = assignment.getAttributeValue().getValue();
182 if (LOGGER.isDebugEnabled()) {
183 LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
186 // Let's parse it into a map using Gson
188 Gson gson = new Gson();
189 @SuppressWarnings("unchecked")
190 Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
191 decisionResponse.getPolicies().add(result);
197 @SuppressWarnings("unchecked")
198 protected PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
200 // Policy name should be at the root
202 String policyName = entrySet.getKey();
203 Map<String, Object> policyDefinition = (Map<String, Object>) entrySet.getValue();
205 // Set it as the policy ID
207 PolicyType newPolicyType = new PolicyType();
208 newPolicyType.setPolicyId(policyName);
210 // Optional description
212 if (policyDefinition.containsKey("description")) {
213 newPolicyType.setDescription(policyDefinition.get("description").toString());
216 // There should be a metadata section
218 if (! policyDefinition.containsKey("metadata")) {
219 throw new ToscaPolicyConversionException(policyName + " missing metadata section");
221 this.fillMetadataSection(newPolicyType,
222 (Map<String, Object>) policyDefinition.get("metadata"));
224 // Set the combining rule
226 newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
228 // Generate the TargetType
230 if (! policyDefinition.containsKey("type")) {
231 throw new ToscaPolicyConversionException(policyName + " missing type value");
233 if (! policyDefinition.containsKey("version")) {
234 throw new ToscaPolicyConversionException(policyName + " missing version value");
236 TargetType target = this.generateTargetType(policyName,
237 policyDefinition.get("type").toString(),
238 policyDefinition.get("version").toString());
239 newPolicyType.setTarget(target);
241 // Now create the Permit Rule
242 // No target since the policy has a target
245 RuleType rule = new RuleType();
246 rule.setDescription("Default is to PERMIT if the policy matches.");
247 rule.setRuleId(policyName + ":rule");
248 rule.setEffect(EffectType.PERMIT);
249 rule.setTarget(new TargetType());
251 // Now represent the policy as Json
253 JSONObject jsonObligation = new JSONObject();
254 jsonObligation.put(policyName, policyDefinition);
255 addObligation(rule, jsonObligation);
257 // Add the rule to the policy
259 newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
261 // Return our new policy
263 return newPolicyType;
267 * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
269 * @param policy Policy Object to store the metadata
270 * @param metadata The Metadata TOSCA Map
271 * @return Same Policy Object
272 * @throws ToscaPolicyConversionException If there is something missing from the metadata
274 protected PolicyType fillMetadataSection(PolicyType policy,
275 Map<String, Object> metadata) throws ToscaPolicyConversionException {
276 if (! metadata.containsKey("policy-id")) {
277 throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
280 // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
283 if (! metadata.containsKey("policy-version")) {
284 throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
287 // Add in the Policy Version
289 policy.setVersion(metadata.get("policy-version").toString());
294 protected TargetType generateTargetType(String policyId, String policyType, String policyTypeVersion) {
296 // Create all the match's that are possible
298 // This is for the Policy Id
300 MatchType matchPolicyId = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
301 XACML3.ID_FUNCTION_STRING_EQUAL,
303 XACML3.ID_DATATYPE_STRING,
304 ToscaDictionary.ID_RESOURCE_POLICY_ID,
305 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
307 // This is for the Policy Type
309 MatchType matchPolicyType = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
310 XACML3.ID_FUNCTION_STRING_EQUAL,
312 XACML3.ID_DATATYPE_STRING,
313 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
314 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
316 // This is for the Policy Type version
318 MatchType matchPolicyTypeVersion = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
319 XACML3.ID_FUNCTION_STRING_EQUAL,
321 XACML3.ID_DATATYPE_STRING,
322 ToscaDictionary.ID_RESOURCE_POLICY_TYPE_VERSION,
323 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
325 // This is our outer AnyOf - which is an OR
327 AnyOfType anyOf = new AnyOfType();
329 // Create AllOf (AND) of just Policy Id
331 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyId));
333 // Create AllOf (AND) of just Policy Type
335 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType));
337 // Create AllOf (AND) of Policy Type and Policy Type Version
339 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType, matchPolicyTypeVersion));
341 // Now we can create the TargetType, add the top-level anyOf (OR),
342 // and return the value.
344 TargetType target = new TargetType();
345 target.getAnyOf().add(anyOf);
349 protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) {
351 // Convert the YAML Policy to JSON Object
353 if (LOGGER.isDebugEnabled()) {
354 LOGGER.debug("JSON DCAE Policy {}{}", System.lineSeparator(), jsonPolicy);
357 // Create an AttributeValue for it
359 AttributeValueType value = new AttributeValueType();
360 value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
361 value.getContent().add(jsonPolicy.toString());
363 // Create our AttributeAssignmentExpression where we will
364 // store the contents of the policy in JSON format.
366 AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType();
367 expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue());
368 ObjectFactory factory = new ObjectFactory();
369 expressionType.setExpression(factory.createAttributeValue(value));
371 // Create an ObligationExpression for it
373 ObligationExpressionType obligation = new ObligationExpressionType();
374 obligation.setFulfillOn(EffectType.PERMIT);
375 obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
376 obligation.getAttributeAssignmentExpression().add(expressionType);
378 // Now we can add it into the rule
380 ObligationExpressionsType obligations = new ObligationExpressionsType();
381 obligations.getObligationExpression().add(obligation);
382 rule.setObligationExpressions(obligations);