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.List;
42 import java.util.Map.Entry;
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;
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;
66 public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator {
68 private static final Logger LOGGER = LoggerFactory.getLogger(StdCombinedPolicyResultsTranslator.class);
70 public StdCombinedPolicyResultsTranslator() {
74 @SuppressWarnings("unchecked")
76 public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject)
77 throws ToscaPolicyConversionException {
81 List<PolicyType> scannedPolicies = new ArrayList<>();
83 // Iterate each of the Policies
85 List<Object> policies = (List<Object>) toscaObject.get("policies");
86 for (Object policyObject : policies) {
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);
95 // Convert this policy
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);
105 // Convert and add in the new policy
107 scannedPolicies.add(policy);
111 return scannedPolicies;
115 public Request convertRequest(DecisionRequest request) {
116 LOGGER.debug("Converting Request {}", request);
118 return RequestParser.parseRequest(StdCombinedPolicyRequest.createInstance(request));
119 } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
120 LOGGER.error("Failed to convert DecisionRequest: {}", e);
123 // TODO throw exception
129 public DecisionResponse convertResponse(Response xacmlResponse) {
130 LOGGER.debug("Converting Response {}", xacmlResponse);
131 DecisionResponse decisionResponse = new DecisionResponse();
133 // Iterate through all the results
135 for (Result xacmlResult : xacmlResponse.getResults()) {
139 if (xacmlResult.getDecision() == Decision.PERMIT) {
143 decisionResponse.setPolicies(new ArrayList<>());
145 // Go through obligations
147 for (Obligation obligation : xacmlResult.getObligations()) {
148 LOGGER.debug("Obligation: {}", obligation);
149 for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
150 LOGGER.debug("Attribute Assignment: {}", assignment);
152 // We care about the content attribute
154 if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS
155 .equals(assignment.getAttributeId())) {
157 // The contents are in Json form
159 Object stringContents = assignment.getAttributeValue().getValue();
160 if (LOGGER.isDebugEnabled()) {
161 LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
164 // Let's parse it into a map using Gson
166 Gson gson = new Gson();
167 @SuppressWarnings("unchecked")
168 Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
169 decisionResponse.getPolicies().add(result);
174 decisionResponse.setErrorMessage("A better error message");
178 return decisionResponse;
181 @SuppressWarnings("unchecked")
182 protected PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
184 // Policy name should be at the root
186 String policyName = entrySet.getKey();
187 Map<String, Object> policyDefinition = (Map<String, Object>) entrySet.getValue();
189 // Set it as the policy ID
191 PolicyType newPolicyType = new PolicyType();
192 newPolicyType.setPolicyId(policyName);
194 // Optional description
196 if (policyDefinition.containsKey("description")) {
197 newPolicyType.setDescription(policyDefinition.get("description").toString());
200 // There should be a metadata section
202 if (! policyDefinition.containsKey("metadata")) {
203 throw new ToscaPolicyConversionException(policyName + " missing metadata section");
205 this.fillMetadataSection(newPolicyType,
206 (Map<String, Object>) policyDefinition.get("metadata"));
208 // Set the combining rule
210 newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
212 // Generate the TargetType
215 // There should be a metadata section
217 if (! policyDefinition.containsKey("type")) {
218 throw new ToscaPolicyConversionException(policyName + " missing type value");
220 if (! policyDefinition.containsKey("version")) {
221 throw new ToscaPolicyConversionException(policyName + " missing version value");
223 TargetType target = this.generateTargetType(policyName,
224 policyDefinition.get("type").toString(),
225 policyDefinition.get("version").toString());
226 newPolicyType.setTarget(target);
228 // Now create the Permit Rule
229 // No target since the policy has a target
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());
238 // Now represent the policy as Json
240 JSONObject jsonObligation = new JSONObject();
241 jsonObligation.put(policyName, policyDefinition);
242 addObligation(rule, jsonObligation);
244 // Add the rule to the policy
246 newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
248 // Return our new policy
250 return newPolicyType;
254 * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
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
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");
267 // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
270 if (! metadata.containsKey("policy-version")) {
271 throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
274 // Add in the Policy Version
276 policy.setVersion(metadata.get("policy-version").toString());
281 protected TargetType generateTargetType(String policyId, String policyType, String policyTypeVersion) {
283 // Create all the match's that are possible
285 // This is for the Policy Id
287 MatchType matchPolicyId = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
288 XACML3.ID_FUNCTION_STRING_EQUAL,
290 XACML3.ID_DATATYPE_STRING,
291 ToscaDictionary.ID_RESOURCE_POLICY_ID,
292 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
294 // This is for the Policy Type
296 MatchType matchPolicyType = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
297 XACML3.ID_FUNCTION_STRING_EQUAL,
299 XACML3.ID_DATATYPE_STRING,
300 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
301 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
303 // This is for the Policy Type version
305 MatchType matchPolicyTypeVersion = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
306 XACML3.ID_FUNCTION_STRING_EQUAL,
308 XACML3.ID_DATATYPE_STRING,
309 ToscaDictionary.ID_RESOURCE_POLICY_TYPE_VERSION,
310 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
312 // This is our outer AnyOf - which is an OR
314 AnyOfType anyOf = new AnyOfType();
316 // Create AllOf (AND) of just Policy Id
318 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyId));
320 // Create AllOf (AND) of just Policy Type
322 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType));
324 // Create AllOf (AND) of Policy Type and Policy Type Version
326 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchPolicyType, matchPolicyTypeVersion));
328 // Now we can create the TargetType, add the top-level anyOf (OR),
329 // and return the value.
331 TargetType target = new TargetType();
332 target.getAnyOf().add(anyOf);
336 protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) {
338 // Convert the YAML Policy to JSON Object
340 if (LOGGER.isDebugEnabled()) {
341 LOGGER.debug("JSON DCAE Policy {}{}", System.lineSeparator(), jsonPolicy);
344 // Create an AttributeValue for it
346 AttributeValueType value = new AttributeValueType();
347 value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
348 value.getContent().add(jsonPolicy.toString());
350 // Create our AttributeAssignmentExpression where we will
351 // store the contents of the policy in JSON format.
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));
358 // Create an ObligationExpression for it
360 ObligationExpressionType obligation = new ObligationExpressionType();
361 obligation.setFulfillOn(EffectType.PERMIT);
362 obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
363 obligation.getAttributeAssignmentExpression().add(expressionType);
365 // Now we can add it into the rule
367 ObligationExpressionsType obligations = new ObligationExpressionsType();
368 obligations.getObligationExpression().add(obligation);
369 rule.setObligationExpressions(obligations);