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.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;
 
  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.ObjectFactory;
 
  41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
 
  42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
 
  43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
 
  44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 
  45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
 
  46 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 
  47 import org.onap.policy.models.decisions.concepts.DecisionResponse;
 
  48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
  49 import org.onap.policy.pdp.xacml.application.common.OnapObligation;
 
  50 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
 
  51 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
 
  52 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
 
  53 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
 
  54 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
 
  55 import org.slf4j.Logger;
 
  56 import org.slf4j.LoggerFactory;
 
  58 public abstract class StdBaseTranslator implements ToscaPolicyTranslator {
 
  59     private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class);
 
  60     private static final ObjectFactory factory = new ObjectFactory();
 
  62     public static final String POLICY_ID = "policy-id";
 
  63     public static final String POLICY_VERSION = "policy-version";
 
  66     public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
 
  67         throw new ToscaPolicyConversionException("Please override convertPolicy");
 
  71     public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
 
  76     public DecisionResponse convertResponse(Response xacmlResponse) {
 
  77         LOGGER.info("Converting Response {}", xacmlResponse);
 
  78         var decisionResponse = new DecisionResponse();
 
  82         decisionResponse.setPolicies(new HashMap<>());
 
  84         // Iterate through all the results
 
  86         for (Result xacmlResult : xacmlResponse.getResults()) {
 
  90             if (xacmlResult.getDecision() == Decision.PERMIT) {
 
  92                 // Go through obligations
 
  94                 scanObligations(xacmlResult.getObligations(), decisionResponse);
 
  98                 scanAdvice(xacmlResult.getAssociatedAdvice(), decisionResponse);
 
 101                 // Return error information back
 
 103                 decisionResponse.setStatus("error");
 
 104                 decisionResponse.setMessage(xacmlResult.getStatus().getStatusMessage());
 
 108         return decisionResponse;
 
 112      * scanObligations - scans the list of obligations and make appropriate method calls to process
 
 113      * obligations. This method must be overridden and be implemented for the specific application as
 
 114      * obligations may have different expected attributes per application.
 
 116      * @param obligations Collection of obligation objects
 
 117      * @param decisionResponse DecisionResponse object used to store any results from obligations.
 
 119     protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse);
 
 122      * scanAdvice - scans the list of advice and make appropriate call to process the advice. This method
 
 123      * can be overridden for each specific application as advice may have different expected attributes per
 
 126      * @param advice Collection of Advice objects
 
 127      * @param decisionResponse DecisionResponse object used to store any results from advice.
 
 129     protected abstract void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse);
 
 132      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
 
 134      * @param policy Policy Object to store the metadata
 
 135      * @param map The Metadata TOSCA Map
 
 136      * @return Same Policy Object
 
 137      * @throws ToscaPolicyConversionException If there is something missing from the metadata
 
 139     protected PolicyType fillMetadataSection(PolicyType policy,
 
 140             Map<String, String> map) throws ToscaPolicyConversionException {
 
 142         // Ensure the policy-id exists - we don't use it here. It
 
 143         // is saved in the TOSCA Policy Name field.
 
 145         if (! map.containsKey(POLICY_ID)) {
 
 146             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata " + POLICY_ID);
 
 149         // Ensure the policy-version exists
 
 151         if (! map.containsKey(POLICY_VERSION)) {
 
 152             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata "
 
 156         // Add in the Policy Version
 
 158         policy.setVersion(map.get(POLICY_VERSION));
 
 163      * addObligation - general code to add a json policy as an obligation. Probably could just
 
 164      * return the obligation only instead of adding it directly to a rule/policy/policyset.
 
 165      * But this is fine for now.
 
 167      * @param <T> RuleType, PolicyType, PolicySetType object
 
 168      * @Param policyId The policy-id
 
 169      * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
 
 170      * @param jsonPolicy JSON String representation of policy.
 
 171      * @param weight Weighting for the policy (optional)
 
 172      * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
 
 174     protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight,
 
 177         // Creating obligation for returning policy
 
 179         LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight,
 
 180                 XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
 
 182         // Create our OnapObligation
 
 184         var onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight);
 
 186         // Generate the obligation
 
 188         ObligationExpressionType obligation = onapObligation.generateObligation();
 
 190         // Now we can add it into the rule/policy/policyset
 
 192         var obligations = new ObligationExpressionsType();
 
 193         obligations.getObligationExpression().add(obligation);
 
 194         if (ruleOrPolicy instanceof RuleType) {
 
 195             ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
 
 196         } else if (ruleOrPolicy instanceof PolicyType) {
 
 197             ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
 
 198         } else if (ruleOrPolicy instanceof PolicySetType) {
 
 199             ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
 
 201             LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass());
 
 204         // Return as a convenience
 
 210      * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
 
 211      * to match on a specific TOSCA Policy Type.
 
 213      * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
 
 214      * @return AnyOfType object
 
 216     protected AnyOfType generateAnyOfForPolicyType(String type) {
 
 218         // Create the match for the policy type
 
 220         var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
 
 221                 XACML3.ID_FUNCTION_STRING_EQUAL,
 
 223                 XACML3.ID_DATATYPE_STRING,
 
 224                 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
 
 225                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
 
 227         // Add it to an AnyOfType object
 
 229         var anyOf = new AnyOfType();
 
 230         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
 
 232         // Return new AnyOfType
 
 238      * generateConditionForPolicyType - create a ConditionType XACML object
 
 239      * that is able to determine if a request specifies a specific policy type
 
 240      * that the policy is created from, only then is the rule applied. If the
 
 241      * request doesn't even care about the policy type (eg it is missing) then
 
 242      * return the rule should not apply.
 
 244      * @param type PolicyType (eg. onap.policies.Foo
 
 245      * @return ConditionType object
 
 247     protected ConditionType generateConditionForPolicyType(String type) {
 
 249         // Create an ApplyType that checks if the request contains the
 
 250         // policy-type attribute
 
 252         var designator = new AttributeDesignatorType();
 
 253         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
 
 254         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
 
 255         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
 
 257         var applyBagSize = new ApplyType();
 
 258         applyBagSize.setDescription("Get the size of policy-type attributes");
 
 259         applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());
 
 261         var valueZero = new AttributeValueType();
 
 262         valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
 
 263         valueZero.getContent().add("0");    // Yes really - represent as a string
 
 265         applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));
 
 267         var applyGreaterThan = new ApplyType();
 
 268         applyGreaterThan.setDescription("Does the policy-type attribute exist?");
 
 269         applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());
 
 271         applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
 
 272         applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));
 
 275         // Create an apply type that checks the actual value
 
 277         var value = new AttributeValueType();
 
 278         value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
 
 279         value.getContent().add(type);
 
 282         // Create string-is-in apply - which determines if the policy-type
 
 283         // is in the request bag of resources for policy-type
 
 285         var applyIsIn = new ApplyType();
 
 286         applyIsIn.setDescription("Is this policy-type in the list?");
 
 287         applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
 
 288         applyIsIn.getExpression().add(factory.createAttributeValue(value));
 
 289         applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));
 
 292         // Create our outer apply
 
 294         var applyOr = new ApplyType();
 
 295         applyOr.setDescription("IF exists and is equal");
 
 296         applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());
 
 298         applyOr.getExpression().add(factory.createApply(applyGreaterThan));
 
 299         applyOr.getExpression().add(factory.createApply(applyIsIn));
 
 302         // Finally create the condition
 
 304         var condition = new ConditionType();
 
 306         condition.setExpression(factory.createApply(applyOr));