2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2021 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.Advice;
26 import com.att.research.xacml.api.Attribute;
27 import com.att.research.xacml.api.AttributeCategory;
28 import com.att.research.xacml.api.Decision;
29 import com.att.research.xacml.api.Obligation;
30 import com.att.research.xacml.api.Request;
31 import com.att.research.xacml.api.Response;
32 import com.att.research.xacml.api.Result;
33 import com.att.research.xacml.api.XACML3;
34 import java.util.Collection;
35 import java.util.HashMap;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
50 import org.onap.policy.models.decisions.concepts.DecisionRequest;
51 import org.onap.policy.models.decisions.concepts.DecisionResponse;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
53 import org.onap.policy.pdp.xacml.application.common.OnapObligation;
54 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
55 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
56 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
57 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
58 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 public abstract class StdBaseTranslator implements ToscaPolicyTranslator {
63 private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class);
64 private static final ObjectFactory factory = new ObjectFactory();
68 protected boolean booleanReturnAttributes = false;
72 protected boolean booleanReturnSingleValueAttributesAsCollection = false;
74 public static final String POLICY_ID = "policy-id";
75 public static final String POLICY_VERSION = "policy-version";
78 public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
79 throw new ToscaPolicyConversionException("Please override convertPolicy");
83 public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
88 public DecisionResponse convertResponse(Response xacmlResponse) {
89 LOGGER.info("Converting Response {}", xacmlResponse);
90 var decisionResponse = new DecisionResponse();
94 decisionResponse.setPolicies(new HashMap<>());
96 // Iterate through all the results
98 for (Result xacmlResult : xacmlResponse.getResults()) {
102 if (xacmlResult.getDecision() == Decision.PERMIT) {
104 // Go through obligations
106 scanObligations(xacmlResult.getObligations(), decisionResponse);
110 scanAdvice(xacmlResult.getAssociatedAdvice(), decisionResponse);
113 // Return error information back
115 decisionResponse.setStatus("error");
116 decisionResponse.setMessage(xacmlResult.getStatus().getStatusMessage());
121 if (booleanReturnAttributes) {
122 scanAttributes(xacmlResult.getAttributes(), decisionResponse);
126 return decisionResponse;
130 * scanObligations - scans the list of obligations and make appropriate method calls to process
131 * obligations. This method must be overridden and be implemented for the specific application as
132 * obligations may have different expected attributes per application.
134 * @param obligations Collection of obligation objects
135 * @param decisionResponse DecisionResponse object used to store any results from obligations.
137 protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse);
140 * scanAdvice - scans the list of advice and make appropriate call to process the advice. This method
141 * can be overridden for each specific application as advice may have different expected attributes per
144 * @param advice Collection of Advice objects
145 * @param decisionResponse DecisionResponse object used to store any results from advice.
147 protected abstract void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse);
150 * scanAttributes - scans the attributes that are returned in the XACML Decision and puts them into the
151 * DecisionResponse object.
153 * @param attributeCategories Collection of AttributeCategory objects
154 * @param decisionResponse DecisionResponse object used to store any attributes
156 protected void scanAttributes(Collection<AttributeCategory> attributeCategories,
157 DecisionResponse decisionResponse) {
158 var returnedAttributes = new HashMap<String, Object>();
159 for (AttributeCategory attributeCategory : attributeCategories) {
160 var mapCategory = new HashMap<String, Object>();
161 for (Attribute attribute : attributeCategory.getAttributes()) {
163 // Most attributes have a single value, thus the collection is not necessary to
164 // return. However, we will allow this to be configurable.
166 if (! booleanReturnSingleValueAttributesAsCollection && attribute.getValues().size() == 1) {
167 var iterator = attribute.getValues().iterator();
168 var value = iterator.next();
169 mapCategory.put(attribute.getAttributeId().stringValue(), value.getValue().toString());
171 mapCategory.put(attribute.getAttributeId().stringValue(), attribute.getValues());
174 returnedAttributes.put(attributeCategory.getCategory().stringValue(), mapCategory);
176 if (! returnedAttributes.isEmpty()) {
177 decisionResponse.setAttributes(returnedAttributes);
182 * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
184 * @param policy Policy Object to store the metadata
185 * @param map The Metadata TOSCA Map
186 * @return Same Policy Object
187 * @throws ToscaPolicyConversionException If there is something missing from the metadata
189 protected PolicyType fillMetadataSection(PolicyType policy,
190 Map<String, String> map) throws ToscaPolicyConversionException {
192 // Ensure the policy-id exists - we don't use it here. It
193 // is saved in the TOSCA Policy Name field.
195 if (! map.containsKey(POLICY_ID)) {
196 throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata " + POLICY_ID);
199 // Ensure the policy-version exists
201 if (! map.containsKey(POLICY_VERSION)) {
202 throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata "
206 // Add in the Policy Version
208 policy.setVersion(map.get(POLICY_VERSION));
213 * addObligation - general code to add a json policy as an obligation. Probably could just
214 * return the obligation only instead of adding it directly to a rule/policy/policyset.
215 * But this is fine for now.
217 * @param <T> RuleType, PolicyType, PolicySetType object
218 * @Param policyId The policy-id
219 * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
220 * @param jsonPolicy JSON String representation of policy.
221 * @param weight Weighting for the policy (optional)
222 * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
224 protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight,
227 // Creating obligation for returning policy
229 LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight,
230 XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
232 // Create our OnapObligation
234 var onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight);
236 // Generate the obligation
238 ObligationExpressionType obligation = onapObligation.generateObligation();
240 // Now we can add it into the rule/policy/policyset
242 var obligations = new ObligationExpressionsType();
243 obligations.getObligationExpression().add(obligation);
244 if (ruleOrPolicy instanceof RuleType) {
245 ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
246 } else if (ruleOrPolicy instanceof PolicyType) {
247 ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
248 } else if (ruleOrPolicy instanceof PolicySetType) {
249 ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
251 LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass());
254 // Return as a convenience
260 * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
261 * to match on a specific TOSCA Policy Type.
263 * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
264 * @return AnyOfType object
266 protected AnyOfType generateAnyOfForPolicyType(String type) {
268 // Create the match for the policy type
270 var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
271 XACML3.ID_FUNCTION_STRING_EQUAL,
273 XACML3.ID_DATATYPE_STRING,
274 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
275 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
277 // Add it to an AnyOfType object
279 var anyOf = new AnyOfType();
280 anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
282 // Return new AnyOfType
288 * generateConditionForPolicyType - create a ConditionType XACML object
289 * that is able to determine if a request specifies a specific policy type
290 * that the policy is created from, only then is the rule applied. If the
291 * request doesn't even care about the policy type (eg it is missing) then
292 * return the rule should not apply.
294 * @param type PolicyType (eg. onap.policies.Foo
295 * @return ConditionType object
297 protected ConditionType generateConditionForPolicyType(String type) {
299 // Create an ApplyType that checks if the request contains the
300 // policy-type attribute
302 var designator = new AttributeDesignatorType();
303 designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
304 designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
305 designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
307 var applyBagSize = new ApplyType();
308 applyBagSize.setDescription("Get the size of policy-type attributes");
309 applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());
311 var valueZero = new AttributeValueType();
312 valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
313 valueZero.getContent().add("0"); // Yes really - represent as a string
315 applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));
317 var applyGreaterThan = new ApplyType();
318 applyGreaterThan.setDescription("Does the policy-type attribute exist?");
319 applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());
321 applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
322 applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));
325 // Create an apply type that checks the actual value
327 var value = new AttributeValueType();
328 value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
329 value.getContent().add(type);
332 // Create string-is-in apply - which determines if the policy-type
333 // is in the request bag of resources for policy-type
335 var applyIsIn = new ApplyType();
336 applyIsIn.setDescription("Is this policy-type in the list?");
337 applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
338 applyIsIn.getExpression().add(factory.createAttributeValue(value));
339 applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));
342 // Create our outer apply
344 var applyOr = new ApplyType();
345 applyOr.setDescription("IF exists and is equal");
346 applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());
348 applyOr.getExpression().add(factory.createApply(applyGreaterThan));
349 applyOr.getExpression().add(factory.createApply(applyIsIn));
352 // Finally create the condition
354 var condition = new ConditionType();
356 condition.setExpression(factory.createApply(applyOr));