508bc24500ecb1742a67191729220f8fa726303c
[policy/xacml-pdp.git] /
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.Decision;
26 import com.att.research.xacml.api.Obligation;
27 import com.att.research.xacml.api.Request;
28 import com.att.research.xacml.api.Response;
29 import com.att.research.xacml.api.Result;
30 import com.att.research.xacml.api.XACML3;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.Map;
34 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
35 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
36 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
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;
57
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();
61
62     public static final String POLICY_ID = "policy-id";
63     public static final String POLICY_VERSION = "policy-version";
64
65     @Override
66     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
67         throw new ToscaPolicyConversionException("Please override convertPolicy");
68     }
69
70     @Override
71     public Request convertRequest(DecisionRequest request) {
72         return null;
73     }
74
75     @Override
76     public DecisionResponse convertResponse(Response xacmlResponse) {
77         LOGGER.info("Converting Response {}", xacmlResponse);
78         DecisionResponse decisionResponse = new DecisionResponse();
79         //
80         // Setup policies
81         //
82         decisionResponse.setPolicies(new HashMap<>());
83         //
84         // Iterate through all the results
85         //
86         for (Result xacmlResult : xacmlResponse.getResults()) {
87             //
88             // Check the result
89             //
90             if (xacmlResult.getDecision() == Decision.PERMIT) {
91                 //
92                 // Go through obligations
93                 //
94                 scanObligations(xacmlResult.getObligations(), decisionResponse);
95             } else {
96                 //
97                 // TODO we have to return an ErrorResponse object instead
98                 //
99                 decisionResponse.setStatus("A better error message");
100             }
101         }
102
103         return decisionResponse;
104     }
105
106     /**
107      * scanObligations - scans the list of obligations and make appropriate method calls to process
108      * obligations. This method must be overridden and be implemented for the specific application as
109      * obligations may have different expected attributes per application.
110      *
111      * @param obligations Collection of obligation objects
112      * @param decisionResponse DecisionResponse object used to store any results from obligations.
113      */
114     protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse);
115
116     /**
117      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
118      *
119      * @param policy Policy Object to store the metadata
120      * @param map The Metadata TOSCA Map
121      * @return Same Policy Object
122      * @throws ToscaPolicyConversionException If there is something missing from the metadata
123      */
124     protected PolicyType fillMetadataSection(PolicyType policy,
125             Map<String, String> map) throws ToscaPolicyConversionException {
126         //
127         // Ensure the policy-id exists - we don't use it here. It
128         // is saved in the TOSCA Policy Name field.
129         //
130         if (! map.containsKey(POLICY_ID)) {
131             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata " + POLICY_ID);
132         }
133         //
134         // Ensure the policy-version exists
135         //
136         if (! map.containsKey(POLICY_VERSION)) {
137             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata "
138                     + POLICY_VERSION);
139         }
140         //
141         // Add in the Policy Version
142         //
143         policy.setVersion(map.get(POLICY_VERSION));
144         return policy;
145     }
146
147     /**
148      * addObligation - general code to add a json policy as an obligation. Probably could just
149      * return the obligation only instead of adding it directly to a rule/policy/policyset.
150      * But this is fine for now.
151      *
152      * @param <T> RuleType, PolicyType, PolicySetType object
153      * @Param policyId The policy-id
154      * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
155      * @param jsonPolicy JSON String representation of policy.
156      * @param weight Weighting for the policy (optional)
157      * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
158      */
159     protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight,
160             String policyType) {
161         //
162         // Creating obligation for returning policy
163         //
164         LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight,
165                 XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
166         //
167         // Create our OnapObligation
168         //
169         OnapObligation onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight);
170         //
171         // Generate the obligation
172         //
173         ObligationExpressionType obligation = onapObligation.generateObligation();
174         //
175         // Now we can add it into the rule/policy/policyset
176         //
177         ObligationExpressionsType obligations = new ObligationExpressionsType();
178         obligations.getObligationExpression().add(obligation);
179         if (ruleOrPolicy instanceof RuleType) {
180             ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
181         } else if (ruleOrPolicy instanceof PolicyType) {
182             ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
183         } else if (ruleOrPolicy instanceof PolicySetType) {
184             ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
185         } else {
186             LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass());
187         }
188         //
189         // Return as a convenience
190         //
191         return ruleOrPolicy;
192     }
193
194     /**
195      * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
196      * to match on a specific TOSCA Policy Type.
197      *
198      * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
199      * @return AnyOfType object
200      */
201     protected AnyOfType generateAnyOfForPolicyType(String type) {
202         //
203         // Create the match for the policy type
204         //
205         MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
206                 XACML3.ID_FUNCTION_STRING_EQUAL,
207                 type,
208                 XACML3.ID_DATATYPE_STRING,
209                 ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
210                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
211         //
212         // Add it to an AnyOfType object
213         //
214         AnyOfType anyOf = new AnyOfType();
215         anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
216         //
217         // Return new AnyOfType
218         //
219         return anyOf;
220     }
221
222     /**
223      * generateConditionForPolicyType - create a ConditionType XACML object
224      * that is able to determine if a request specifies a specific policy type
225      * that the policy is created from, only then is the rule applied. If the
226      * request doesn't even care about the policy type (eg it is missing) then
227      * return the rule should not apply.
228      *
229      * @param type PolicyType (eg. onap.policies.Foo
230      * @return ConditionType object
231      */
232     protected ConditionType generateConditionForPolicyType(String type) {
233         //
234         // Create an ApplyType that checks if the request contains the
235         // policy-type attribute
236         //
237         AttributeDesignatorType designator = new AttributeDesignatorType();
238         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
239         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
240         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
241
242         ApplyType applyBagSize = new ApplyType();
243         applyBagSize.setDescription("Get the size of policy-type attributes");
244         applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());
245
246         AttributeValueType valueZero = new AttributeValueType();
247         valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
248         valueZero.getContent().add("0");    // Yes really - represent as a string
249
250         applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));
251
252         ApplyType applyGreaterThan = new ApplyType();
253         applyGreaterThan.setDescription("Does the policy-type attribute exist?");
254         applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());
255
256         applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
257         applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));
258
259         //
260         // Create an apply type that checks the actual value
261         //
262         AttributeValueType value = new AttributeValueType();
263         value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
264         value.getContent().add(type);
265
266         //
267         // Create string-is-in apply - which determines if the policy-type
268         // is in the request bag of resources for policy-type
269         //
270         ApplyType applyIsIn = new ApplyType();
271         applyIsIn.setDescription("Is this policy-type in the list?");
272         applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
273         applyIsIn.getExpression().add(factory.createAttributeValue(value));
274         applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));
275
276         //
277         // Create our outer apply
278         //
279         ApplyType applyOr = new ApplyType();
280         applyOr.setDescription("IF exists and is equal");
281         applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());
282
283         applyOr.getExpression().add(factory.createApply(applyGreaterThan));
284         applyOr.getExpression().add(factory.createApply(applyIsIn));
285
286         //
287         // Finally create the condition
288         //
289         ConditionType condition = new ConditionType();
290
291         condition.setExpression(factory.createApply(applyOr));
292
293         return condition;
294     }
295
296 }